├── examples ├── gssproxy.conf.in ├── 80-httpd.conf.in ├── 24-nfs-server.conf.in ├── proxymech.conf.in └── 99-network-fs-clients.conf.in ├── po └── README ├── src ├── mechglue │ ├── README │ └── gpp_display_status.c ├── gp_creds.h ├── gp_log.h ├── gp_debug.h ├── gp_config.h ├── gp_export.h ├── gp_rpc_release_handle.c ├── gp_selinux.h ├── gp_rpc_process.h ├── gp_rpc_wrap_size_limit.c ├── gp_log.c ├── client │ ├── gpm_wrap_size_limit.c │ ├── gpm_get_mic.c │ ├── gpm_verify_mic.c │ ├── gpm_inquire_context.c │ ├── gpm_wrap.c │ ├── gpm_unwrap.c │ ├── gpm_release_handle.c │ ├── gpm_display_status.c │ └── gpm_accept_sec_context.c ├── gp_rpc_creds.h ├── gp_conv.h ├── gp_rpc_verify_mic.c ├── gp_rpc_get_mic.c ├── gp_debug.c ├── gp_rpc_debug.h ├── gp_rpc_wrap.c ├── gp_rpc_import_and_canon_name.c ├── gp_rpc_unwrap.c ├── extract_ccache.c └── gp_common.h ├── docs ├── Releases │ ├── v0.8.2.md │ ├── README.md │ ├── v0.6.2.md │ ├── v0.6.1.md │ ├── v0.2.1.md │ ├── v0.5.1.md │ ├── v0.8.3.md │ ├── v0.4.1.md │ ├── v0.2.3.md │ ├── v0.3.1.md │ ├── v0.2.2.md │ ├── v0.3.0.md │ ├── v0.1.2.md │ ├── v0.8.1.md │ ├── v0.7.0.md │ ├── v0.8.4.md │ ├── v0.4.0.md │ ├── v0.6.0.md │ ├── v0.2.0.md │ ├── v0.1.0.md │ ├── v0.8.0.md │ └── v0.5.0.md ├── ReleaseProcess.md ├── network_fs_clients.md ├── KRB5_TRACE.md ├── ProtocolDocumentation.md ├── Userproxy.md └── Apache.md ├── systemd ├── gssuserproxy.service.in ├── gssuserproxy.socket.in └── gssproxy.service.in ├── version.m4 ├── external ├── libpopt.m4 ├── libkeyutils.m4 ├── systemd.m4 ├── docbook.m4 ├── selinux.m4 ├── sizes.m4 ├── platform.m4 └── dinglibs.m4 ├── STYLE.txt ├── rpcgen ├── README ├── gp_xdr.h └── gp_xdr.c ├── tests ├── t_utils.h ├── t_acquire.py ├── t_interpose.py ├── t_names.py ├── t_setcredopt.py ├── scripts │ └── dlopen.sh ├── t_cred_store.py ├── Makefile.am ├── t_program.py ├── t_accept.c ├── t_reloading.py ├── t_multi_key.py ├── t_utils.c ├── t_cred_store.c ├── t_init.c ├── userproxytest.c ├── runtests.py ├── t_acquire.c └── t_impersonate.py ├── .gitignore ├── COPYING ├── BUILD.txt ├── .github └── workflows │ ├── coverity.yml │ └── ci.yaml ├── README.md ├── NOTES ├── contrib └── gssproxy.spec.in ├── x-files └── gp_rpc.x └── man └── Makefile.am /examples/gssproxy.conf.in: -------------------------------------------------------------------------------- 1 | [gssproxy] 2 | -------------------------------------------------------------------------------- /po/README: -------------------------------------------------------------------------------- 1 | PLACEHOLDER 2 | po files here 3 | -------------------------------------------------------------------------------- /src/mechglue/README: -------------------------------------------------------------------------------- 1 | This directory now contains the actual mechglue plugin, 2 | client functions have been moved to the client directory. 3 | -------------------------------------------------------------------------------- /docs/Releases/v0.8.2.md: -------------------------------------------------------------------------------- 1 | Highlights: 2 | - Fix a crash bug in v0.8.1 3 | 4 | Simo Sorce (1): 5 | - Change the way we handle encrypted buffers 6 | -------------------------------------------------------------------------------- /docs/Releases/README.md: -------------------------------------------------------------------------------- 1 | This directory is historical. 2 | Releases are document on the Github 3 | [Releases](https://github.com/gssapi/gssproxy/releases) page. 4 | -------------------------------------------------------------------------------- /examples/80-httpd.conf.in: -------------------------------------------------------------------------------- 1 | [service/HTTP] 2 | mechs = krb5 3 | cred_store = keytab:/etc/gssproxy/http.keytab 4 | cred_store = ccache:/var/lib/gssproxy/clients/krb5cc_%U 5 | euid = apache 6 | -------------------------------------------------------------------------------- /examples/24-nfs-server.conf.in: -------------------------------------------------------------------------------- 1 | [service/nfs-server] 2 | mechs = krb5 3 | socket = /run/gssproxy.sock 4 | cred_store = keytab:/etc/krb5.keytab 5 | trusted = yes 6 | kernel_nfsd = yes 7 | euid = 0 8 | -------------------------------------------------------------------------------- /docs/Releases/v0.6.2.md: -------------------------------------------------------------------------------- 1 | Highlights: 2 | 3 | - Fix a crash bug 4 | 5 | 6 | Robbie Harwood (2): 7 | 8 | - Fix allocation of cred_store to have two extra slots 9 | - Release version 0.6.2 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/proxymech.conf.in: -------------------------------------------------------------------------------- 1 | # GSS-API mechanism plugins 2 | # 3 | # Mechanism Name Object Identifier Shared Library Path Other Options 4 | gssproxy_v1 2.16.840.1.113730.3.8.15.1 @libdir@/gssproxy/proxymech.so 5 | -------------------------------------------------------------------------------- /systemd/gssuserproxy.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=GSS User Proxy 3 | Documentation=man:gssproxy(8) 4 | 5 | [Service] 6 | Type=notify 7 | StandardError=journal 8 | ExecStart=@sbindir@/gssproxy -i -u 9 | Restart=on-failure 10 | -------------------------------------------------------------------------------- /systemd/gssuserproxy.socket.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=GSS User Proxy 3 | 4 | [Socket] 5 | Priority=6 6 | Backlog=5 7 | ListenStream=%t/gssproxy/default.sock 8 | SocketMode=0600 9 | 10 | [Install] 11 | WantedBy=sockets.target 12 | -------------------------------------------------------------------------------- /version.m4: -------------------------------------------------------------------------------- 1 | # Primary version number 2 | m4_define([VERSION_NUMBER], [0.9.2]) 3 | 4 | # If the PRERELEASE_VERSION_NUMBER is set, we'll append 5 | # it to the release tag when creating an RPM or SRPM 6 | m4_define([PRERELEASE_VERSION_NUMBER], []) 7 | 8 | -------------------------------------------------------------------------------- /docs/Releases/v0.6.1.md: -------------------------------------------------------------------------------- 1 | Highlights: 2 | 3 | - Fix an error with missing keytab 4 | 5 | 6 | Robbie Harwood (1): 7 | 8 | - Release version 0.6.1 9 | 10 | 11 | Simo Sorce (1): 12 | 13 | - Missing keytab should not be fatal 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/99-network-fs-clients.conf.in: -------------------------------------------------------------------------------- 1 | [service/network-fs-clients] 2 | mechs = krb5 3 | cred_store = keytab:/etc/krb5.keytab 4 | cred_store = ccache:FILE:@gpclidir@/krb5cc_%U 5 | cred_store = client_keytab:@gpclidir@/%U.keytab 6 | cred_usage = initiate 7 | allow_any_uid = yes 8 | trusted = yes 9 | euid = 0 10 | min_lifetime = 60 11 | -------------------------------------------------------------------------------- /external/libpopt.m4: -------------------------------------------------------------------------------- 1 | AC_DEFUN([WITH_POPT], 2 | [ 3 | POPT_OBJ="" 4 | AC_SUBST(POPT_OBJ) 5 | AC_SUBST(POPT_LIBS) 6 | AC_SUBST(POPT_CFLAGS) 7 | 8 | AC_CHECK_HEADERS([popt.h], 9 | [AC_CHECK_LIB(popt, poptGetContext, [ POPT_LIBS="-lpopt" ], [AC_MSG_ERROR([POPT must support poptGetContext])])], 10 | [AC_MSG_ERROR([POPT development libraries not installed])] 11 | ) 12 | ]) 13 | -------------------------------------------------------------------------------- /STYLE.txt: -------------------------------------------------------------------------------- 1 | We adopt a coding style derived from http://freeipa.org/page/Coding_Style 2 | 3 | There are minor differences including ut not limited to the following: 4 | - due to the fact we interface to GSSAPI which heavily used typedefs they 5 | are not actively discouraged in this code base 6 | 7 | - Initializations and NULL-checks should use the appropriate GSS_C_NO_XXX 8 | initializers 9 | 10 | 11 | -------------------------------------------------------------------------------- /rpcgen/README: -------------------------------------------------------------------------------- 1 | 2 | This file have been generated from .x files in ../x-files 3 | Please do not directly edit these .c/.h files. 4 | Instead please edit the original .x files and then use rpcgen to re-generate 5 | the .c/.h files. 6 | 7 | NOTE: C files have been slightly edited to avoid compile warnings, please 8 | keep the changes if you regenerate them. 9 | 10 | Also note that gp_rpc.x must conform to RFC1831 11 | -------------------------------------------------------------------------------- /rpcgen/gp_xdr.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2013 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #ifndef _GP_XDR_H_ 4 | #define _GP_XDR_H_ 5 | 6 | #include "gssrpc/rpc.h" 7 | 8 | /* Equivalent to xdrptoc_t but with proper arguments so that modern 9 | * compilers do not complain */ 10 | typedef int xdrfn(XDR *, void *); 11 | 12 | #define xdr_u_quad_t gp_xdr_uint64_t 13 | 14 | bool_t gp_xdr_uint64_t(XDR *xdrs, uint64_t *objp); 15 | 16 | #endif /* _GP_XDR_H_ */ 17 | -------------------------------------------------------------------------------- /docs/Releases/v0.2.1.md: -------------------------------------------------------------------------------- 1 | ## Highlights 2 | 3 | 4 | - Minor bugfix release. No new features. 5 | 6 | 7 | 8 | ## Detailed Changelog 9 | 10 | 11 | Günther Deschner (6): 12 | 13 | - Rename option_is_set to gp_boolean_is_true. 14 | - Make gp_boolean_is_true non-static. 15 | - Use gp_boolean_is_true from interposer plugin's GSS_USE_PROXY check. 16 | - Make sure non-root users can access gpstatedir. 17 | - Add --with-gpstate-path=PATH configure switch. 18 | - Bump version for 0.2.1 release. 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/Releases/v0.5.1.md: -------------------------------------------------------------------------------- 1 | ## Highlights 2 | 3 | 4 | - Fix bug with export creds that can cause NFS failures 5 | - Fix bug with uid/pid/gid changes that can break autofs 6 | 7 | 8 | ## Detailed Changelog 9 | 10 | Andrew Elble (1): 11 | 12 | - Fix typo in gp_get_export_creds_type() 13 | 14 | 15 | Robbie Harwood (3): 16 | 17 | - Fix return check on gp_conv_gssx_to_name 18 | - Use new socket if uid, pid, or gid changes 19 | - Release version 0.5.1 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/gp_creds.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #ifndef _GP_CREDS_H_ 4 | #define _GP_CREDS_H_ 5 | 6 | #include "config.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define CRED_TYPE_NONE 0x00 13 | #define CRED_TYPE_UNIX 0x01 14 | #define CRED_TYPE_SELINUX 0x02 15 | 16 | struct gp_creds { 17 | int type; 18 | struct ucred ucred; 19 | }; 20 | 21 | #endif /* _GP_CREDS_H_ */ 22 | -------------------------------------------------------------------------------- /external/libkeyutils.m4: -------------------------------------------------------------------------------- 1 | AC_SUBST(KEYUTILS_LIBS) 2 | 3 | AC_CHECK_HEADERS([keyutils.h], 4 | [AC_CHECK_LIB([keyutils], [add_key], 5 | [AC_DEFINE(USE_KEYRING, 1, [Define if the keyring should be used]) 6 | KEYUTILS_LIBS="-lkeyutils" 7 | ], 8 | [AC_MSG_WARN([No usable keyutils library found])] 9 | )], 10 | [AC_MSG_WARN([keyutils header files are not available])] 11 | ) 12 | -------------------------------------------------------------------------------- /docs/Releases/v0.8.3.md: -------------------------------------------------------------------------------- 1 | Highlights: 2 | - We're on github now 3 | 4 | Guiyao (1): 5 | - Unlock cond\_mutex before pthread exit in gp\_worker\_main() 6 | 7 | Orion Poplawski (1): 8 | - Replace /var/run -> /run in gssproxy.service 9 | 10 | Pat Riehecky (1): 11 | - Delay gssproxy start until after network.target 12 | 13 | Robbie Harwood (2): 14 | - Avoid uninitialized free when allocating buffers 15 | - Update NFS service name in systemd unit 16 | 17 | Simo Sorce (2): 18 | - Use getrandom() for picking xid initial offset 19 | - Fix handling of selinux context when NULL 20 | 21 | Tomáš Chvátal (1): 22 | - Support for running tests on openSUSE 23 | -------------------------------------------------------------------------------- /src/gp_log.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2012 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #ifndef _GP_LOG_H_ 4 | #define _GP_LOG_H_ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | extern bool gp_syslog_status; 11 | 12 | #define MAX_LOG_LINE 1024 13 | #define GPERROR(...) syslog(LOG_ERR, __VA_ARGS__); 14 | #define GPAUDIT(...) syslog(LOG_INFO, __VA_ARGS__); 15 | 16 | void gp_logging_init(void); 17 | 18 | void gp_fmt_status(gss_OID mech, uint32_t maj, uint32_t min, 19 | char *buf, size_t buf_size); 20 | 21 | void gp_log_status(gss_OID mech, uint32_t maj, uint32_t min); 22 | 23 | #endif /* _GP_LOG_H_ */ 24 | -------------------------------------------------------------------------------- /external/systemd.m4: -------------------------------------------------------------------------------- 1 | dnl A macro to check presence of libsystemd on the system 2 | AC_DEFUN([AM_CHECK_SYSTEMD], 3 | [ 4 | PKG_CHECK_MODULES([SYSTEMD_DAEMON], 5 | [libsystemd], 6 | [AC_DEFINE_UNQUOTED([HAVE_SYSTEMD_DAEMON], 1, 7 | [Build with libsystemd support]) 8 | HAVE_SYSTEMD_DAEMON=yes 9 | AC_MSG_NOTICE([Build with libsystemd support])], 10 | [HAVE_SYSTEMD_DAEMON=no 11 | AC_MSG_NOTICE([Build without libsystemd support])]) 12 | 13 | AM_CONDITIONAL([HAVE_SYSTEMD_DAEMON], [test x"$HAVE_SYSTEMD_DAEMON" = xyes]) 14 | ]) 15 | -------------------------------------------------------------------------------- /docs/Releases/v0.4.1.md: -------------------------------------------------------------------------------- 1 | ## Highlights 2 | 3 | 4 | - Fixes a bug in generating the example config files 5 | - Other minor !Coverity/Clang fixes for issues introduced by the last version 6 | 7 | 8 | ## Detailed Changelog 9 | 10 | Lukas Slebodnik (4): 11 | 12 | - Fix warning value stored to 'ret' is never read 13 | - Remove unused parameter from get_pipe_name 14 | - Include header file with prototypes in implementation module 15 | - Suppress warning: use after free 16 | 17 | 18 | Simo Sorce (5): 19 | 20 | - Switch to use pkg-config for krb5-gssapi 21 | - Use pkg-config for krb5 libs too 22 | - Fix handling of context initialization 23 | - Fix configuration file substitutions 24 | - Release version 0.4.1 25 | 26 | 27 | -------------------------------------------------------------------------------- /rpcgen/gp_xdr.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2013 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "rpcgen/gp_xdr.h" 4 | 5 | bool_t gp_xdr_uint64_t(XDR *xdrs, uint64_t *objp) 6 | { 7 | uint32_t h; 8 | uint32_t l; 9 | 10 | switch(xdrs->x_op) { 11 | case XDR_ENCODE: 12 | h = (uint32_t)((*objp) >> 32); 13 | l = (uint32_t)(*objp); 14 | if (!xdr_u_int32(xdrs, &h) || !xdr_u_int32(xdrs, &l)) { 15 | return FALSE; 16 | } 17 | return TRUE; 18 | case XDR_DECODE: 19 | if (!xdr_u_int32(xdrs, &h) || !xdr_u_int32(xdrs, &l)) { 20 | return FALSE; 21 | } 22 | *objp = (((uint64_t)h) << 32) | l; 23 | return TRUE; 24 | case XDR_FREE: 25 | return TRUE; 26 | default: 27 | return FALSE; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/Releases/v0.2.3.md: -------------------------------------------------------------------------------- 1 | ## Highlights 2 | 3 | 4 | - Minor bugfix release. No new features. 5 | 6 | 7 | 8 | ## Detailed Changelog 9 | 10 | Günther Deschner (10): 11 | 12 | - Make sure dlopen.sh is part of the tarball 13 | - Fix realloc size in gp_get_cred_environment(). 14 | - Add "make test_proxymech" to provided specfile. 15 | - systemd: Make sure we start before nfs-secure services. 16 | - systemd: add require for the nfs kernel modules. 17 | - gssproxy: report an error message on event loop failure. 18 | - Require libverto-tevent to make sure libverto initialization succeeds 19 | - Use verbose ding-libs error reporting when config parsing failed. 20 | - Add Requires: libini_config >= 1.0.0.1 to the rpm spec file. 21 | - Bump version for 0.2.3 release. 22 | 23 | 24 | Simo Sorce (1): 25 | 26 | - Fix nfsd socket 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/gp_debug.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011,2018 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #ifndef _GP_DEBUG_H_ 4 | #define _GP_DEBUG_H_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define GP_INFO_DEBUG_LVL 1 12 | 13 | extern int gp_debug; 14 | 15 | void gp_debug_toggle(int); 16 | void gp_debug_printf(const char *format, ...); 17 | void gp_debug_time_printf(const char *format, ...); 18 | void gp_debug_set_conn_id(int id); 19 | void gp_debug_set_krb5_tracing_fn(void (*fn)(int)); 20 | 21 | #define GPDEBUG(...) do { \ 22 | if (gp_debug) { \ 23 | gp_debug_time_printf(__VA_ARGS__); \ 24 | } \ 25 | } while(0) 26 | 27 | #define GPDEBUGN(lvl, ...) do { \ 28 | if (lvl <= gp_debug) { \ 29 | gp_debug_time_printf(__VA_ARGS__); \ 30 | } \ 31 | } while(0) 32 | 33 | void gp_log_failure(gss_OID mech, uint32_t maj, uint32_t min); 34 | 35 | #endif /* _GP_DEBUG_H_ */ 36 | -------------------------------------------------------------------------------- /tests/t_utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "config.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define STDIN_FD 0 12 | #define STDOUT_FD 1 13 | #define MAX_RPC_SIZE 1024*1024 14 | 15 | #define discard_const(ptr) ((void *)((uintptr_t)(ptr))) 16 | 17 | #define DEBUG(...) do { \ 18 | char _msg[4096]; \ 19 | int _snret; \ 20 | _snret = snprintf(_msg, 4096, __VA_ARGS__); \ 21 | fprintf(stderr, "%s[%s:%d]: %s", argv[0], __FUNCTION__, __LINE__, _msg); \ 22 | if (_snret >= 4096) fprintf(stderr, " [TRUNCATED]\n"); \ 23 | fflush(stderr); \ 24 | } while(0); 25 | 26 | int t_send_buffer(int fd, char *buf, uint32_t len); 27 | int t_recv_buffer(int fd, char *buf, uint32_t *len); 28 | 29 | void t_log_failure(gss_OID mech, uint32_t maj, uint32_t min); 30 | 31 | int t_string_to_name(const char *string, gss_name_t *name, gss_OID type); 32 | -------------------------------------------------------------------------------- /docs/Releases/v0.3.1.md: -------------------------------------------------------------------------------- 1 | ## Highlights 2 | 3 | 4 | - Fix use of gssproxy for client initiation 5 | - Add new enforcing and filtering options for context initialization 6 | - Fix potential thread safety issues 7 | 8 | 9 | 10 | ## Detailed Changelog 11 | 12 | Günther Deschner (1): 13 | 14 | - Change version to 0.3.1 15 | 16 | 17 | Simo Sorce (14): 18 | 19 | - Preserve requested flags and lifetime 20 | - Add way to return regular oid from special 21 | - Fix calling gpm_inquire_cred_by_mech 22 | - Fix continuations in context establishment calls 23 | - Autoinitialize creds on init_sec_context 24 | - Try impersonation even when a name is not provided 25 | - config: Add code to source flag filters 26 | - server: Implement flag filtering enforcement 27 | - man: Describe new flag filtering/enforcing options 28 | - config: Do not modify const strings 29 | - creds: Allow admins to define only client creds 30 | - Use secure_getenv in client and mechglue module 31 | - Add Thread-safe implementation of strerror() 32 | - Use gp_strerror() everywhere instead of strerror() 33 | 34 | 35 | -------------------------------------------------------------------------------- /tests/t_acquire.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # Copyright (C) 2015,2016 - GSS-Proxy contributors; see COPYING for the license. 3 | 4 | from testlib import * 5 | 6 | def run(testdir, env, conf, expected_failure=False): 7 | print("Testing basic acquire creds...", file=sys.stderr) 8 | conf['prefix'] = str(cmd_index) 9 | 10 | svc_keytab = os.path.join(testdir, SVC_KTNAME) 11 | testenv = {'KRB5CCNAME': os.path.join(testdir, 't' + conf['prefix'] + 12 | '_acquire.ccache'), 13 | 'KRB5_KTNAME': conf['keytab'], 14 | 'KRB5_TRACE': os.path.join(testdir, 't' + conf['prefix'] + 15 | '_acquire.trace'), 16 | 'GSS_USE_PROXY': 'yes', 17 | 'GSSPROXY_BEHAVIOR': 'REMOTE_FIRST'} 18 | testenv.update(env) 19 | 20 | cmd = "./tests/t_acquire " + conf['svc_name'] 21 | 22 | return run_testcase_cmd(testenv, conf, cmd, "Acquire", expected_failure) 23 | 24 | if __name__ == "__main__": 25 | from runtests import runtests_main 26 | runtests_main(["t_acquire.py"]) 27 | -------------------------------------------------------------------------------- /external/docbook.m4: -------------------------------------------------------------------------------- 1 | dnl Checks for tools needed to generate manual pages 2 | AC_DEFUN([CHECK_XML_TOOLS], 3 | [ 4 | AC_PATH_PROG([XSLTPROC], [xsltproc]) 5 | if test ! -x "$XSLTPROC"; then 6 | AC_MSG_ERROR([Could not find xsltproc]) 7 | fi 8 | 9 | AC_PATH_PROG([XMLLINT], [xmllint]) 10 | if test ! -x "$XMLLINT"; then 11 | AC_MSG_ERROR([Could not find xmllint]) 12 | fi 13 | 14 | AC_PATH_PROG([XMLCATALOG], [xmlcatalog]) 15 | if test ! -x "$XMLCATALOG"; then 16 | AC_MSG_ERROR([Could not find xmlcatalog]) 17 | fi 18 | ]) 19 | 20 | dnl Usage: 21 | dnl CHECK_STYLESHEET_URI(FILE, URI, [FRIENDLY-NAME]) 22 | dnl Checks if the XML catalog given by FILE exists and 23 | dnl if a particular URI appears in the XML catalog 24 | AC_DEFUN([CHECK_STYLESHEET], 25 | [ 26 | AC_CHECK_FILE($1, [], [AC_MSG_ERROR([could not find XML catalog])]) 27 | 28 | AC_MSG_CHECKING([for ifelse([$3],,[$2],[$3]) in XML catalog]) 29 | if AC_RUN_LOG([$XMLCATALOG --noout "$1" "$2" >&2]); then 30 | AC_MSG_RESULT([yes]) 31 | else 32 | AC_MSG_ERROR([could not find ifelse([$3],,[$2],[$3]) in XML catalog]) 33 | fi 34 | ]) 35 | 36 | -------------------------------------------------------------------------------- /external/selinux.m4: -------------------------------------------------------------------------------- 1 | dnl A macro to check the availability of SELinux 2 | AC_DEFUN([AM_CHECK_SELINUX], 3 | [ 4 | AC_CHECK_HEADERS(selinux/selinux.h, 5 | [AC_CHECK_LIB(selinux, is_selinux_enabled, 6 | [SELINUX_LIBS="-lselinux"], 7 | [AC_MSG_ERROR([SELinux library is missing])] 8 | ) 9 | ], 10 | [AC_MSG_ERROR([SELinux headers are missing])]) 11 | AC_SUBST(SELINUX_LIBS) 12 | ]) 13 | 14 | dnl A macro to check the availability of SELinux management library 15 | AC_DEFUN([AM_CHECK_SEMANAGE], 16 | [ 17 | AC_CHECK_HEADERS(semanage/semanage.h, 18 | [AC_CHECK_LIB(semanage, semanage_handle_create, 19 | [SEMANAGE_LIBS="-lsemanage"], 20 | [AC_MSG_ERROR([libsemanage is missing])] 21 | ) 22 | ], 23 | [AC_MSG_ERROR([libsemanage is missing])]) 24 | AC_SUBST(SEMANAGE_LIBS) 25 | ]) 26 | -------------------------------------------------------------------------------- /docs/Releases/v0.2.2.md: -------------------------------------------------------------------------------- 1 | ## Highlights 2 | 3 | 4 | - Minor bugfix release. No new features. 5 | 6 | 7 | 8 | ## Detailed Changelog 9 | 10 | Günther Deschner (14): 11 | 12 | - Add --with-gpp-default-behavior configure switch. 13 | - Make error message in read_config() more precise, we fail in that case. 14 | - Fix unresolved symbol gp_boolean_is_true() in mechglue plugin. 15 | - Fix reallocation in gp_dinglibs_get_string_array(). 16 | - Fix typo in gssi_import_name_by_mech(). 17 | - Use counter when freeing cred_store configuration. 18 | - Don't forget to free gp_ini_context struct in load_config(). 19 | - Fix two memleaks in the configuration code. 20 | - Add dlopen script to check for unresolved symbols. 21 | - Disable gss_export_name_composite() for now. 22 | - Overwrite existing GSS_USE_PROXY variable in the server. 23 | - Fix documentation of "mechs" parameter in gssproxy.conf(5). 24 | - Bump version for 0.2.2 release. 25 | - Make sure dlopen.sh is part of the tarball 26 | 27 | 28 | Simo Sorce (3): 29 | 30 | - Neutralize gssi_export_name. 31 | - Fix secondary socket detection at runtime. 32 | - Fix socket error handling. 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .deps/ 3 | ABOUT-NLS 4 | Makefile 5 | Makefile.in 6 | aclocal.m4 7 | autom4te.cache/ 8 | build/ 9 | config.h 10 | config.h.in 11 | config.log 12 | config.status 13 | configure 14 | gssproxy 15 | *.o 16 | libtool 17 | m4/ 18 | man.stamp 19 | Makefile.in.in 20 | Makevars.template 21 | Rules-quot 22 | boldquot.sed 23 | en@boldquot.header 24 | en@quot.header 25 | insert-header.sin 26 | quot.sed 27 | remove-potcdate.sin 28 | stamp-h1 29 | *.8 30 | *.5 31 | config.h.in~ 32 | cscope.out 33 | dict.symbols 34 | .dirstamp 35 | cli_srv_conn 36 | *.la 37 | *.lo 38 | .libs/ 39 | cli_srv_comm 40 | gssproxy.spec 41 | interposetest 42 | userproxytest 43 | gssproxy.service 44 | gssuserproxy.service 45 | gssuserproxy.socket 46 | ar-lib 47 | compile 48 | config.guess 49 | config.rpath 50 | config.sub 51 | depcomp 52 | install-sh 53 | ltmain.sh 54 | missing 55 | mkinstalldirs 56 | examples/24-nfs-server.conf 57 | examples/80-httpd.conf 58 | examples/99-nfs-client.conf 59 | examples/*.conf 60 | man/gssproxy-mech.8.xml 61 | testdir/ 62 | tests/__pycache__/ 63 | tests/t_accept 64 | tests/t_acquire 65 | tests/t_cred_store 66 | tests/t_impersonate 67 | tests/t_init 68 | tests/t_names 69 | tests/t_setcredopt 70 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GSS-PROXY 2 | 3 | Copyright (C) 2011 Red Hat, Inc. 4 | Copyright (C) 2011-2015 the GSS-PROXY contributors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the "Software"), 8 | to deal in the Software without restriction, including without limitation 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | DEALINGS IN THE SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /tests/t_interpose.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # Copyright (C) 2014,2015,2016 - GSS-Proxy contributors; see COPYING for the license 3 | 4 | from testlib import * 5 | 6 | def run(testdir, env, conf): 7 | print("Testing interposer...", file=sys.stderr) 8 | conf['prefix'] = str(cmd_index) 9 | logfile = os.path.join(conf['logpath'], "test_%d.log" % cmd_index) 10 | logfile = open(logfile, 'a') 11 | 12 | ienv = {"KRB5CCNAME": os.path.join(testdir, 'interpose_ccache'), 13 | "KRB5_KTNAME": os.path.join(testdir, SVC_KTNAME)} 14 | ienv.update(env) 15 | usr_keytab = os.path.join(testdir, USR_KTNAME) 16 | 17 | ksetup = subprocess.Popen(["kinit", "-kt", usr_keytab, USR_NAME], 18 | stdout=logfile, stderr=logfile, 19 | env=ienv, preexec_fn=os.setsid) 20 | ksetup.wait() 21 | if ksetup.returncode != 0: 22 | raise ValueError('Kinit %s failed' % USR_NAME) 23 | 24 | cmd = " ".join(["./interposetest", "-t", "host@%s" % WRAP_HOSTNAME]) 25 | return run_testcase_cmd(ienv, conf, cmd, "Interpose") 26 | 27 | if __name__ == "__main__": 28 | from runtests import runtests_main 29 | runtests_main(["t_interpose.py"]) 30 | -------------------------------------------------------------------------------- /docs/Releases/v0.3.0.md: -------------------------------------------------------------------------------- 1 | ## Highlights 2 | 3 | 4 | - Add support for impersonation (depends on s4u2self/s4u2proxy on the KDC) 5 | - Add support for new rpc.gssd mode of operation that forks and changes uid 6 | - Add 2 new options allow_any_uid and cred_usage 7 | 8 | 9 | 10 | ## Detailed Changelog 11 | 12 | Günther Deschner (5): 13 | 14 | - Further improve debugging, mention servicename, socket and euid. 15 | - Use right signedness for creds buffer. 16 | - Fix resource leak in gpm_accept_sec_context(). 17 | - docs: autogenerate proxymech manpage. 18 | - docs: Fill in GSSPROXY_BEHAVIOR default setting from configure option. 19 | 20 | 21 | Simo Sorce (14): 22 | 23 | - Split nfs server and client services 24 | - Properly check socket for connection matching. 25 | - Coverity fixes. 26 | - Add service match using SeLinux Context 27 | - Fix selinux option check 28 | - Fix LOCAL_FIRST behavior 29 | - Fix documentation to match reality 30 | - Allow arbitrary users to connect to a service 31 | - Add option to specify allowed usage. 32 | - Add man page entry for allow_any_uid 33 | - Add man page entry for cred_usage 34 | - Move uid to name resolution in its own function. 35 | - Add impersonation support 36 | - Change version to 0.3.0 37 | 38 | 39 | -------------------------------------------------------------------------------- /external/sizes.m4: -------------------------------------------------------------------------------- 1 | # Solaris needs HAVE_LONG_LONG defined 2 | AC_CHECK_TYPES(long long) 3 | 4 | AC_CHECK_SIZEOF(int) 5 | AC_CHECK_SIZEOF(char) 6 | AC_CHECK_SIZEOF(short) 7 | AC_CHECK_SIZEOF(long) 8 | AC_CHECK_SIZEOF(long long) 9 | 10 | if test $ac_cv_sizeof_long_long -lt 8 ; then 11 | AC_MSG_ERROR([SSSD requires long long of 64-bits]) 12 | fi 13 | 14 | AC_CHECK_TYPE(uint_t, unsigned int) 15 | AC_CHECK_TYPE(int8_t, char) 16 | AC_CHECK_TYPE(uint8_t, unsigned char) 17 | AC_CHECK_TYPE(int16_t, short) 18 | AC_CHECK_TYPE(uint16_t, unsigned short) 19 | 20 | if test $ac_cv_sizeof_int -eq 4 ; then 21 | AC_CHECK_TYPE(int32_t, int) 22 | AC_CHECK_TYPE(uint32_t, unsigned int) 23 | elif test $ac_cv_size_long -eq 4 ; then 24 | AC_CHECK_TYPE(int32_t, long) 25 | AC_CHECK_TYPE(uint32_t, unsigned long) 26 | else 27 | AC_MSG_ERROR([LIBREPLACE no 32-bit type found]) 28 | fi 29 | 30 | AC_CHECK_TYPE(int64_t, long long) 31 | AC_CHECK_TYPE(uint64_t, unsigned long long) 32 | 33 | AC_CHECK_TYPE(size_t, unsigned int) 34 | AC_CHECK_TYPE(ssize_t, int) 35 | 36 | AC_CHECK_SIZEOF(off_t) 37 | AC_CHECK_SIZEOF(size_t) 38 | AC_CHECK_SIZEOF(ssize_t) 39 | 40 | AC_CHECK_TYPE(intptr_t, long long) 41 | AC_CHECK_TYPE(uintptr_t, unsigned long long) 42 | AC_CHECK_TYPE(ptrdiff_t, unsigned long long) 43 | 44 | 45 | -------------------------------------------------------------------------------- /docs/Releases/v0.1.2.md: -------------------------------------------------------------------------------- 1 | # Highlights 2 | 3 | - Fixes for various issues found by Coverity 4 | - Switch default configuration backend to use libini_config 5 | 6 | 7 | # Detailed Changelog 8 | 9 | Günther Deschner (4): 10 | 11 | - Add missing newlines to GPDEBUG statements. 12 | - Abstract configuration layer for gssproxy. 13 | - Add dinglibs ini configuration detection and backend. 14 | - Prefer ini_config library support over iniparser support. 15 | 16 | 17 | Simo Sorce (16): 18 | 19 | - Fix unchecked return values found by Coverity 20 | - Fix copy and paste error found by Coverity 21 | - Fix locally dead code error found by coverity 22 | - Fix uninizialized variables found by Coverity 23 | - Fix dereference before null error fund by Coverity 24 | - Fix reporting of wrong error codes 25 | - Fix resource leaks found by Coverity 26 | - Fix infinite loop due to bad sign of variable 27 | - Fix missing break statement found by Coverity 28 | - Fix dereference after null checks found by Coverity 29 | - Use send() in client library to avoid SIGPIPE 30 | - Fix a few more resource leaks 31 | - Fix use of unintialized variable 32 | - Remove unused variables 33 | - Fix tabs in configure.ac 34 | - Release 0.1.1 35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/Releases/v0.8.1.md: -------------------------------------------------------------------------------- 1 | Highlights: 2 | - Fix explicit NULL derereference with tokens of certain enctypes 3 | - Always choose highest requested debug level 4 | - Fixes for running as unprivileged user 5 | 6 | Alexander Scheel (1): 7 | - Permit testing sans Valgrind 8 | 9 | Robbie Harwood (12): 10 | - Clarify debug and debug\_level in man pages 11 | - Always choose highest requested debug level 12 | - Add docs link to README.md 13 | - Add generic service README 14 | - Rename README.style -> STYLE.txt so pagure stops picking it up 15 | - Don't leak sock\_ctx if verto\_add\_io() fails 16 | - Update docs to reflect actual behavior of krb5\_principal 17 | - Sort options in man pages 18 | - Check for test-relevant executables early in suite 19 | - Always initialize out cred in gp\_import\_gssx\_cred() 20 | - Handle gss\_import\_cred() failure when importing gssx creds 21 | - Include length when using krb5\_c\_decrypt() 22 | 23 | Simo Sorce (5): 24 | - Always use the encype we selected 25 | - Use pthread keys for thread local storage 26 | - Close epoll fd within the lock 27 | - Add a safety timeout to epoll 28 | - Reorder functions 29 | 30 | Stanislav Levin (4): 31 | - Fix typo about pid-file 32 | - Retain CAP\_SYS\_PTRACE when running as unpriviliged 33 | - Make build with capabilities optional 34 | - Move run\_as\_user check out of drop\_privs() 35 | -------------------------------------------------------------------------------- /BUILD.txt: -------------------------------------------------------------------------------- 1 | First off, run: 2 | $ autoreconf -f -i 3 | 4 | Then the usual $ ./configure # and $ make # 5 | 6 | In order to build gss-proxy the following development packages are needed 7 | additionally to a ISO C compiler: 8 | 9 | autoconf 10 | automake 11 | docbook-style-xsl 12 | doxygen 13 | findutils 14 | gettext-devel 15 | libini_config-devel 16 | keyutils-libs-devel 17 | krb5-devel 18 | libselinux-devel 19 | libtool 20 | libverto-devel 21 | libxml2 22 | libxslt 23 | m4 24 | make 25 | pkgconfig 26 | popt-devel 27 | 28 | For testing via $ make tests # you additionally need these packages: 29 | 30 | krb5-server 31 | krb5-server-ldap 32 | krb5-workstation 33 | nss_wrapper 34 | openldap-clients 35 | openldap-servers 36 | socket_wrapper 37 | valgrind 38 | 39 | NOTE: The minimum supported Kerberos version is MIT Kerberos 1.14 as it 40 | includes [1] for Microsoft interoperability. gssproxy relies on the 41 | interposer mechanism [1] and so there is no version of gssproxy which will 42 | work before 1.11. Various other features require newer versions of MIT krb5; 43 | patch out at your own risk. 44 | 45 | [1] https://github.com/krb5/krb5/commit/7e6965ae33338216650384ca559d49e90312087a 46 | [2] http://k5wiki.kerberos.org/wiki/Projects/Interposer_Mechanism 47 | -------------------------------------------------------------------------------- /src/gp_config.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011,2012 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #ifndef _GSS_CONFIG_H_ 4 | #define _GSS_CONFIG_H_ 5 | 6 | #define GP_USER_PROXY_WORKERS 2 7 | #define GP_USER_PROXY_SERVICE "user-proxy" 8 | 9 | struct gp_ini_context { 10 | void *private_data; 11 | }; 12 | 13 | int gp_config_init(const char *config_file, const char *config_dir, 14 | struct gp_ini_context *ctx); 15 | int gp_config_get_string(struct gp_ini_context *ctx, 16 | const char *secname, 17 | const char *keyname, 18 | const char **value); 19 | int gp_config_get_string_array(struct gp_ini_context *ctx, 20 | const char *secname, 21 | const char *keyname, 22 | int *num_values, 23 | const char ***values); 24 | int gp_config_get_int(struct gp_ini_context *ctx, 25 | const char *secname, 26 | const char *keyname, 27 | int *value); 28 | int gp_config_get_nsec(struct gp_ini_context *ctx); 29 | char *gp_config_get_secname(struct gp_ini_context *ctx, 30 | int i); 31 | int gp_config_close(struct gp_ini_context *ctx); 32 | 33 | #endif /* _GSS_CONFIG_H_ */ 34 | -------------------------------------------------------------------------------- /docs/ReleaseProcess.md: -------------------------------------------------------------------------------- 1 | # Release Process for GSS-Proxy 2 | 3 | The process is currently quite simple and requires write access to the 4 | project's git repository. 5 | 6 | # Prepare the sources 7 | 8 | ## Version and Tag the release 9 | 10 | - Change in version.m4 with the new version number (ex. 0.1.0) 11 | 12 | - Test locally with "make rpms" that everything builds fine 13 | 14 | - Make a signed tag for the release in the main branch like this: 15 | 16 | ``` 17 | git tag -s v0.1.0 18 | ``` 19 | 20 | This will apply the tag to the last commit 21 | 22 | - Push the tag: 23 | 24 | ``` 25 | git push origin v0.1.0 26 | ``` 27 | 28 | ## Create a release tarball and SHA hash 29 | 30 | - Run the following commands (on a git clean tree, please): 31 | 32 | ``` 33 | autoreconf -f -i 34 | ./configure 35 | make dist 36 | make distcheck 37 | ``` 38 | 39 | ... will generate a tarball named like: gssproxy-0.1.0.tar.gz 40 | 41 | ``` 42 | sha512sum gssproxy-0.1.0.tar.gz > gssproxy-0.1.0.tar.gz.sha512sum.txt 43 | ``` 44 | 45 | ... will generate a file with a sha512 checksum 46 | 47 | ## Publish the release 48 | 49 | - Use Github to create a Release page from the tag. 50 | Use the option to create release notes from the PR log. 51 | 52 | - Announce th new release on the gssproxy mailinglist 53 | (https://lists.fedorahosted.org/archives/lists/gss-proxy.lists.fedorahosted.org/) 54 | -------------------------------------------------------------------------------- /src/gp_export.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #ifndef _GSS_EXPORT_H_ 4 | #define _GSS_EXPORT_H_ 5 | 6 | #include 7 | #include "rpcgen/gss_proxy.h" 8 | 9 | struct gp_call_ctx; 10 | 11 | uint32_t gp_export_gssx_cred(uint32_t *min, struct gp_call_ctx *gpcall, 12 | gss_cred_id_t *in, gssx_cred *out); 13 | uint32_t gp_import_gssx_cred(uint32_t *min, struct gp_call_ctx *gpcall, 14 | gssx_cred *cred, gss_cred_id_t *out); 15 | 16 | int gp_get_exported_context_type(struct gssx_call_ctx *ctx); 17 | int gp_get_continue_needed_type(void); 18 | uint32_t gp_export_ctx_id_to_gssx(uint32_t *min, int type, gss_OID mech, 19 | gss_ctx_id_t *in, gssx_ctx *out); 20 | uint32_t gp_import_gssx_to_ctx_id(uint32_t *min, int type, 21 | gssx_ctx *in, gss_ctx_id_t *out); 22 | 23 | int gp_get_export_creds_type(struct gssx_call_ctx *ctx); 24 | uint32_t gp_export_creds_to_gssx_options(uint32_t *min, int type, 25 | gss_name_t src_name, 26 | gss_const_OID mech_type, 27 | unsigned int *opt_num, 28 | gssx_option **opt_array); 29 | 30 | #endif /* _GSS_EXPORT_H_ */ 31 | -------------------------------------------------------------------------------- /src/gp_rpc_release_handle.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gp_rpc_process.h" 4 | 5 | int gp_release_handle(struct gp_call_ctx *gpcall UNUSED, 6 | union gp_rpc_arg *arg, 7 | union gp_rpc_res *res) 8 | { 9 | struct gssx_arg_release_handle *rha; 10 | struct gssx_res_release_handle *rhr; 11 | uint32_t ret_maj = GSS_S_COMPLETE; 12 | uint32_t ret_min = 0; 13 | int ret; 14 | 15 | rha = &arg->release_handle; 16 | rhr = &res->release_handle; 17 | 18 | GPRPCDEBUG(gssx_arg_release_handle, rha); 19 | 20 | switch (rha->cred_handle.handle_type) { 21 | case GSSX_C_HANDLE_SEC_CTX: 22 | /* We do not need release for any security 23 | * context for now */ 24 | ret_maj = GSS_S_UNAVAILABLE; 25 | ret_min = 0; 26 | break; 27 | case GSSX_C_HANDLE_CRED: 28 | /* We do not need release for any creds now */ 29 | ret_maj = GSS_S_UNAVAILABLE; 30 | ret_min = 0; 31 | break; 32 | default: 33 | ret_maj = GSS_S_CALL_BAD_STRUCTURE; 34 | ret_min = 0; 35 | break; 36 | } 37 | 38 | ret = gp_conv_status_to_gssx(ret_maj, ret_min, GSS_C_NO_OID, 39 | &rhr->status); 40 | GPRPCDEBUG(gssx_res_release_handle, rhr); 41 | 42 | return ret; 43 | } 44 | -------------------------------------------------------------------------------- /.github/workflows/coverity.yml: -------------------------------------------------------------------------------- 1 | name: Coverity Scan 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | schedule: 7 | - cron: '13 2 * * 0' 8 | 9 | jobs: 10 | coverity: 11 | name: Coverity Scan 12 | runs-on: ubuntu-22.04 13 | steps: 14 | - name: Checkout repository 15 | uses: actions/checkout@v2 16 | - name: Install dependencies 17 | run: | 18 | sudo apt-get update 19 | sudo apt-get install -y build-essential autopoint clang gcc docbook-{xsl,xml} libxml2-utils xml-core xsltproc lib{krb5,ini-config,keyutils,popt,selinux1,systemd,verto}-dev lib{nss,socket}-wrapper python3{,-colorama} valgrind krb5-{kdc,admin-server,kdc-ldap} ldap-utils slapd apparmor-utils 20 | - name: Silence AppArmor 21 | run: sudo aa-complain $(which slapd) 22 | - name: Setup 23 | run: | 24 | autoreconf -fiv 25 | ./configure 26 | - name: Check for changes 27 | run: | 28 | echo "RUN_COV=0" >> $GITHUB_ENV; 29 | DIFF=`git log --since=1week | wc -l` 30 | if [ x${DIFF} != "x0" ]; then 31 | echo "RUN_COV=1" >> $GITHUB_ENV; 32 | fi 33 | - name: Coverity Scan 34 | if: env.RUN_COV == 1 35 | uses: vapier/coverity-scan-action@v1 36 | with: 37 | project: "gssproxy" 38 | email: ${{ secrets.COVERITY_SCAN_EMAIL }} 39 | token: ${{ secrets.COVERITY_SCAN_TOKEN }} 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Changelog](https://img.shields.io/github/v/release/gssapi/gssproxy?label=changelog)](https://github.com/gssapi/gssproxy/releases) 2 | [![Build Status](https://github.com/gssapi/gssproxy/actions/workflows/ci.yaml/badge.svg)](https://github.com/gssapi/gssproxy/actions/workflows/ci.yaml) 3 | 4 | This is the gss-proxy project. 5 | 6 | Documentation lives in the [docs folder of this 7 | repository](https://github.com/gssapi/gssproxy/tree/master/docs). 8 | 9 | The goal is to have a GSS-API proxy, with standardizable protocol and a 10 | (somewhat portable) reference client and server implementation. There 11 | are several motivations for this some of which are: 12 | 13 | - Kernel-mode GSS-API applications (CIFS, NFS, AFS, ...) need to be 14 | able to leave all complexity of GSS\_Init/Accept\_sec\_context() out of 15 | the kernel by upcalling to a daemon that does all the dirty work. 16 | 17 | - Isolation and privilege separation for user-mode applications. For 18 | example: letting HTTP servers use but not see the keytabe entries for 19 | HTTP/* principals for accepting security contexts. 20 | 21 | - Possibly an ssh-agent-like SSH agent for GSS credentials -- a 22 | gss-agent. 23 | 24 | gss-proxy uses libverto for dealing with event loops. Note that you need to 25 | have at least one libverto event library installed (e.g. libverto-tevent). 26 | 27 | We have a 28 | [mailing list](https://lists.fedorahosted.org/archives/list/gss-proxy@lists.fedorahosted.org/) 29 | and an IRC channel (#gssapi on [libera.chat](https://libera.chat/)). 30 | -------------------------------------------------------------------------------- /docs/Releases/v0.7.0.md: -------------------------------------------------------------------------------- 1 | Highlights: 2 | 3 | - RHEL-7 support 4 | - Migration to Pagure completed 5 | - Support syncing changed credentials 6 | 7 | Robbie Harwood (13): 8 | - Clean up build flags 9 | - Detect kerberos.schema on RHEL 10 | - Fix behavior when not passed config\_dir on the command line 11 | - Document debug\_level option in gssproxy.conf(5) 12 | - Fix asprintf(3) call in ensure\_segregated\_ccache() 13 | - Appease Coverity 14 | - Remove unused variables in t\_acquire.c 15 | - Markdown conversion of docs from Trac 16 | - Pagure-ify release process 17 | - Remove outdated selinux issue from Apache docs 18 | - Update Apache docs to match latest releases 19 | - Fix broken link in protocol docs 20 | - Release version 0.7.0 21 | 22 | Simo Sorce (16): 23 | - Fix incorrect use of non-null terminated string 24 | - Fix another incorrect use of non-null term. string 25 | - Always check if we have a remote credential 26 | - Fix potential memleak from gpm\_release\_cred 27 | - Local vs Remote cred check fixes 28 | - Add a helper function to pack options 29 | - Add ability to sync creds back on modification 30 | - Do not re-export unchanged creds 31 | - Rework gpp\_cred\_handle management 32 | - Add utility function to compare gssx\_creds 33 | - Always request cred sync on init\_sec\_context 34 | - If credentials changed try to store them 35 | - Change tests to always exercise ccache sycns 36 | - Add support for the NO\_CI\_FLAG credentials option 37 | - Add test to check setting cred options 38 | - Ensure test suite reports failure on traceback 39 | -------------------------------------------------------------------------------- /src/gp_selinux.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2013 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #ifndef _GP_SELINUX_H_ 4 | #define _GP_SELINUX_H_ 5 | 6 | typedef char * SEC_CTX; 7 | 8 | #ifdef HAVE_SELINUX 9 | 10 | #include 11 | #define SELINUX_CTX context_t 12 | #include 13 | 14 | #define SELINUX_context_new context_new 15 | #define SELINUX_context_free context_free 16 | #define SELINUX_context_str context_str 17 | #define SELINUX_context_type_get context_type_get 18 | #define SELINUX_context_user_get context_user_get 19 | #define SELINUX_context_role_get context_role_get 20 | #define SELINUX_context_range_get context_range_get 21 | #define SELINUX_getpeercon getpeercon 22 | #define SELINUX_freecon freecon 23 | 24 | #else /* not HAVE_SELINUX */ 25 | 26 | #define SELINUX_CTX void * 27 | #define SEC_CTX void * 28 | 29 | #define SELINUX_context_new(x) NULL 30 | #define SELINUX_context_free(x) (x) = NULL 31 | #define SELINUX_context_dummy_get(x) "" 32 | #define SELINUX_context_str SELINUX_context_dummy_get 33 | #define SELINUX_context_type_get SELINUX_context_dummy_get 34 | #define SELINUX_context_user_get SELINUX_context_dummy_get 35 | #define SELINUX_context_role_get SELINUX_context_dummy_get 36 | #define SELINUX_context_range_get SELINUX_context_dummy_get 37 | 38 | #include 39 | #define SELINUX_getpeercon(x, y) -1; do { \ 40 | *(y) = NULL; \ 41 | errno = ENOTSUP; \ 42 | } while(0) 43 | 44 | #define SELINUX_freecon(x) (x) = NULL 45 | 46 | #endif /* done HAVE_SELINUX */ 47 | 48 | #endif /*_GP_SELINUX_H_ */ 49 | -------------------------------------------------------------------------------- /tests/t_names.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # Copyright (C) 2020 - GSS-Proxy contributors; see COPYING for the license 3 | 4 | from testlib import * 5 | 6 | def run(testdir, env, conf): 7 | print("Testing name options...", file=sys.stderr) 8 | conf['prefix'] = str(cmd_index) 9 | path_prefix = os.path.join(testdir, 't' + conf['prefix'] + '_') 10 | init_ccache = path_prefix + 'names_init.ccache' 11 | 12 | logfile = os.path.join(conf['logpath'], "test_%d.log" % cmd_index) 13 | logfile = open(logfile, 'a') 14 | 15 | testenv = env.copy() 16 | testenv.update({'KRB5CCNAME': init_ccache}) 17 | 18 | usr_keytab = os.path.join(testdir, USR3_KTNAME) 19 | ksetup = subprocess.Popen(["kinit", "-kt", usr_keytab, USR3_NAME], 20 | stdout=logfile, stderr=logfile, 21 | env=testenv, preexec_fn=os.setsid) 22 | ksetup.wait() 23 | if ksetup.returncode != 0: 24 | raise ValueError("Kinit %s failed" % USR3_NAME) 25 | 26 | 27 | cmd = " ".join(["./tests/t_names", USR3_NAME, HOST_GSS, init_ccache]) 28 | 29 | testenv.update({'KRB5CCNAME': path_prefix + 'names.ccache', 30 | 'KRB5_KTNAME': os.path.join(testdir, SVC_KTNAME), 31 | 'KRB5_TRACE': path_prefix + 'names.trace', 32 | 'GSS_USE_PROXY': 'yes', 33 | 'GSSPROXY_BEHAVIOR': 'REMOTE_ONLY'}) 34 | 35 | return run_testcase_cmd(testenv, conf, cmd, "Check Names") 36 | 37 | if __name__ == "__main__": 38 | from runtests import runtests_main 39 | runtests_main(["t_names.py"]) 40 | -------------------------------------------------------------------------------- /docs/Releases/v0.8.4.md: -------------------------------------------------------------------------------- 1 | Michael Weiser (1): 2 | - Handle impersonation of oneself 3 | 4 | Robbie Harwood (11): 5 | - Document config file non-merging 6 | - Initialize our epoll\_event structures 7 | - Avoid leak of special mechs in gss\_mech\_interposer() 8 | - Fix leak of mech OID in gssi\_inquire\_context() 9 | - Make syslog of call status configurable 10 | - Fix order of socket ev update in init\_sockets() 11 | - Eliminate some leftover dead code 12 | - Update EXTRA\_DIST for missing test files 13 | - Fix warnings in configure programs 14 | - Update vendored ax\_pthread.m4 15 | - Switch to calling distcheck in CI 16 | 17 | Simo Sorce (19): 18 | - Silence gcc on truncation of debug messages 19 | - Work around incorrect gcc restrict warning on asprintf 20 | - Add testlib method to wait for gssproxy reconfiguration 21 | - Expand use of global static mechs to conform to SPI 22 | - Initialize interposed mech list without allocation 23 | - Make sure to free also the remote ctx struct 24 | - Use the correct function to free unused creds 25 | - Fix leaks in our test suite itself 26 | - Always free ciphertext data in gp\_encrypt\_buffer 27 | - Return static oids for naming functions 28 | - Avoid unnecessary allocation in gpm\_inquire\_mechs\_for\_name() 29 | - Use static OIDs in gss\_inquire\_context() 30 | - Add a hidden debug tool to gssproxy 31 | - Implement remoting gss\_localname function. 32 | - Add new test unit for name functions 33 | - Fix various test issues 34 | - Update .gitignore file 35 | - Always shortcircuit mech\_invoke to the local mech 36 | - Clarify mech\_for\_saslname implementation note 37 | 38 | -------------------------------------------------------------------------------- /tests/t_setcredopt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # Copyright (C) 2017 - GSS-Proxy contributors; see COPYING for the license 3 | 4 | from testlib import * 5 | 6 | def run(testdir, env, conf): 7 | print("Testing setting credential options...", file=sys.stderr) 8 | conf['prefix'] = str(cmd_index) 9 | path_prefix = os.path.join(testdir, 't' + conf['prefix'] + '_') 10 | init_ccache = path_prefix + 'sco_init.ccache' 11 | 12 | logfile = os.path.join(conf['logpath'], "test_%d.log" % cmd_index) 13 | logfile = open(logfile, 'a') 14 | 15 | testenv = env.copy() 16 | testenv.update({'KRB5CCNAME': init_ccache}) 17 | 18 | usr_keytab = os.path.join(testdir, USR_KTNAME) 19 | ksetup = subprocess.Popen(["kinit", "-kt", usr_keytab, USR_NAME], 20 | stdout=logfile, stderr=logfile, 21 | env=testenv, preexec_fn=os.setsid) 22 | ksetup.wait() 23 | if ksetup.returncode != 0: 24 | raise ValueError("Kinit %s failed" % USR_NAME) 25 | 26 | 27 | cmd = " ".join(["./tests/t_setcredopt", USR_NAME, HOST_GSS, init_ccache]) 28 | 29 | testenv.update({'KRB5CCNAME': path_prefix + 'sco.ccache', 30 | 'KRB5_KTNAME': os.path.join(testdir, PROXY_KTNAME), 31 | 'KRB5_TRACE': path_prefix + 'sco.trace', 32 | 'GSS_USE_PROXY': 'yes', 33 | 'GSSPROXY_BEHAVIOR': 'REMOTE_FIRST'}) 34 | 35 | return run_testcase_cmd(testenv, conf, cmd, "Set cred options") 36 | 37 | if __name__ == "__main__": 38 | from runtests import runtests_main 39 | runtests_main(["t_setcredopt.py"]) 40 | -------------------------------------------------------------------------------- /tests/scripts/dlopen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | test -n "$TMPDIR" || exit 1 4 | tempdir="$TMPDIR/dlopentest" 5 | mkdir -p $tempdir 6 | cat >> $tempdir/dlopen.c << _EOF 7 | #include 8 | #include 9 | #include 10 | /* Simple program to see if dlopen() would succeed. */ 11 | int main(int argc, char **argv) 12 | { 13 | int i; 14 | char buf[PATH_MAX]; 15 | for (i = 1; i < argc; i++) { 16 | if (dlopen(argv[i], RTLD_NOW)) { 17 | fprintf(stdout, "dlopen() of \"%s\" succeeded.\n", 18 | argv[i]); 19 | } else { 20 | snprintf(buf, sizeof(buf), "./%s", argv[i]); 21 | if (dlopen(buf, RTLD_NOW)) { 22 | fprintf(stdout, "dlopen() of \"./%s\" " 23 | "succeeded.\n", argv[i]); 24 | } else { 25 | fprintf(stdout, "dlopen() of \"%s\" failed: " 26 | "%s\n", argv[i], dlerror()); 27 | return 1; 28 | } 29 | } 30 | } 31 | return 0; 32 | } 33 | _EOF 34 | 35 | for arg in $@ ; do 36 | case "$arg" in 37 | "") 38 | ;; 39 | -I*|-D*|-f*|-m*|-g*|-O*|-W*) 40 | cflags="$cflags $arg" 41 | ;; 42 | -l*|-L*) 43 | ldflags="$ldflags $arg" 44 | ;; 45 | /*) 46 | modules="$modules $arg" 47 | ;; 48 | *) 49 | modules="$modules $arg" 50 | ;; 51 | esac 52 | done 53 | 54 | ${CC:-gcc} $RPM_OPT_FLAGS $CFLAGS -o $tempdir/dlopen $cflags $tempdir/dlopen.c $ldflags -ldl 55 | 56 | retval=0 57 | for module in $modules ; do 58 | case "$module" in 59 | "") 60 | ;; 61 | /*) 62 | $tempdir/dlopen "$module" 63 | retval=$? 64 | ;; 65 | *) 66 | $tempdir/dlopen ./"$module" 67 | retval=$? 68 | ;; 69 | esac 70 | done 71 | 72 | rm -f $tempdir/dlopen $tempdir/dlopen.c 73 | rmdir $tempdir 74 | exit $retval 75 | -------------------------------------------------------------------------------- /tests/t_cred_store.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # Copyright (C) 2016 - GSS-Proxy contributors; see COPYING for the license. 3 | 4 | from testlib import * 5 | 6 | def run(testdir, env, conf): 7 | print("Testing cred store extensions...", file=sys.stderr) 8 | conf['prefix'] = str(cmd_index) 9 | 10 | logfile = os.path.join(conf["logpath"], "test_%d.log" % cmd_index) 11 | logfile = open(logfile, 'a') 12 | 13 | ccache = "FILE:" + os.path.join(testdir, "t" + conf["prefix"] + 14 | "_cred_store.ccache") 15 | testenv = {"KRB5CCNAME": ccache} 16 | testenv.update(env) 17 | usr_keytab = os.path.join(testdir, USR_KTNAME) 18 | ksetup = subprocess.Popen(["kinit", "-kt", usr_keytab, USR_NAME], 19 | stdout=logfile, stderr=logfile, 20 | env=testenv, preexec_fn=os.setsid) 21 | ksetup.wait() 22 | if ksetup.returncode != 0: 23 | raise ValueError("Kinit %s failed" % USR_NAME) 24 | 25 | testenv = {"KRB5_TRACE": os.path.join(testdir, 26 | "t" + conf["prefix"] + ".trace"), 27 | "GSS_USE_PROXY": "yes", 28 | "GSSPROXY_BEHAVIOR": "REMOTE_FIRST"} 29 | testenv.update(env) 30 | temp_ccache = "FILE:" + os.path.join(testdir, "t" + conf["prefix"] + 31 | "_temp.ccache") 32 | cmd = " ".join(["./tests/t_cred_store", ccache, temp_ccache]) 33 | 34 | return run_testcase_cmd(testenv, conf, cmd, "Cred store") 35 | 36 | if __name__ == "__main__": 37 | from runtests import runtests_main 38 | runtests_main(["t_cred_store.py"]) 39 | -------------------------------------------------------------------------------- /src/gp_rpc_process.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #ifndef _GP_RPC_PROCESS_H_ 4 | #define _GP_RPC_PROCESS_H_ 5 | 6 | #include "config.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "gp_common.h" 13 | #include "gp_conv.h" 14 | #include "gp_export.h" 15 | #include "rpcgen/gss_proxy.h" 16 | #include "rpcgen/gp_rpc.h" 17 | #include "gp_rpc_creds.h" 18 | #include "gp_rpc_debug.h" 19 | 20 | struct gssproxy_ctx; 21 | struct gp_service; 22 | 23 | #define gp_exec_std_args struct gp_call_ctx *gpcall, \ 24 | union gp_rpc_arg *arg, \ 25 | union gp_rpc_res *res 26 | 27 | #define GP_EXEC_UNUSED_FUNC(name) \ 28 | int name(struct gp_call_ctx *gpcall UNUSED, \ 29 | union gp_rpc_arg *arg UNUSED, \ 30 | union gp_rpc_res *res UNUSED) \ 31 | { return 0; } 32 | 33 | int gp_indicate_mechs(gp_exec_std_args); 34 | int gp_get_call_context(gp_exec_std_args); 35 | int gp_import_and_canon_name(gp_exec_std_args); 36 | int gp_export_cred(gp_exec_std_args); 37 | int gp_import_cred(gp_exec_std_args); 38 | int gp_acquire_cred(gp_exec_std_args); 39 | int gp_store_cred(gp_exec_std_args); 40 | int gp_init_sec_context(gp_exec_std_args); 41 | int gp_accept_sec_context(gp_exec_std_args); 42 | int gp_release_handle(gp_exec_std_args); 43 | int gp_get_mic(gp_exec_std_args); 44 | int gp_verify_mic(gp_exec_std_args); 45 | int gp_wrap(gp_exec_std_args); 46 | int gp_unwrap(gp_exec_std_args); 47 | int gp_wrap_size_limit(gp_exec_std_args); 48 | 49 | #endif /* _GP_RPC_PROCESS_H_ */ 50 | -------------------------------------------------------------------------------- /tests/Makefile.am: -------------------------------------------------------------------------------- 1 | t_acquire_SOURCES = \ 2 | t_utils.c \ 3 | t_acquire.c 4 | 5 | t_acquire_LDADD = \ 6 | $(GSSAPI_LIBS) 7 | 8 | t_accept_SOURCES = \ 9 | t_utils.c \ 10 | t_accept.c 11 | 12 | t_accept_LDADD = \ 13 | $(GSSAPI_LIBS) 14 | 15 | t_cred_store_SOURCES = \ 16 | t_utils.c \ 17 | t_cred_store.c 18 | 19 | t_cred_store_LDADD = \ 20 | $(GSSAPI_LIBS) 21 | 22 | t_impersonate_SOURCES = \ 23 | t_utils.c \ 24 | t_impersonate.c 25 | 26 | t_impersonate_LDADD = \ 27 | $(GSSAPI_LIBS) 28 | 29 | t_init_SOURCES = \ 30 | t_utils.c \ 31 | t_init.c 32 | 33 | t_init_LDADD = \ 34 | $(GSSAPI_LIBS) 35 | 36 | t_names_SOURCES = \ 37 | t_utils.c \ 38 | t_names.c 39 | 40 | t_names_LDADD = \ 41 | $(GSSAPI_LIBS) 42 | 43 | t_setcredopt_SOURCES = \ 44 | t_utils.c \ 45 | t_setcredopt.c 46 | 47 | t_setcredopt_LDADD = \ 48 | $(GSSAPI_LIBS) 49 | 50 | check_PROGRAMS = \ 51 | t_acquire \ 52 | t_cred_store \ 53 | t_impersonate \ 54 | t_accept \ 55 | t_init \ 56 | t_names \ 57 | t_setcredopt \ 58 | $(NULL) 59 | 60 | if HAVE_SYSTEMD_DAEMON 61 | userproxytest_SOURCES = \ 62 | userproxytest.c 63 | 64 | check_PROGRAMS += userproxytest 65 | endif 66 | 67 | noinst_PROGRAMS = $(check_PROGRAMS) 68 | 69 | noinst_HEADERS = \ 70 | t_utils.h 71 | 72 | EXTRA_DIST = \ 73 | runtests.py \ 74 | t_acquire.py \ 75 | t_basic.py \ 76 | t_cred_store.py \ 77 | testlib.py \ 78 | t_impersonate.py \ 79 | t_interpose.py \ 80 | t_multi_key.py \ 81 | t_names.py \ 82 | t_program.py \ 83 | t_reloading.py \ 84 | t_setcredopt.py \ 85 | $(NULL) 86 | 87 | all: $(check_PROGRAMS) 88 | -------------------------------------------------------------------------------- /src/mechglue/gpp_display_status.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2012 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gss_plugin.h" 4 | 5 | OM_uint32 gssi_display_status(OM_uint32 *minor_status, 6 | OM_uint32 status_value, 7 | int status_type, 8 | const gss_OID mech_type, 9 | OM_uint32 *message_context, 10 | gss_buffer_t status_string) 11 | { 12 | OM_uint32 maj, min, val; 13 | 14 | GSSI_TRACE(); 15 | 16 | /* This function is only ever called for minor status values */ 17 | if (status_type != GSS_C_MECH_CODE) { 18 | return GSS_S_BAD_STATUS; 19 | } 20 | 21 | val = gpp_unmap_error(status_value); 22 | 23 | maj = gpm_display_status(&min, 24 | val, 25 | GSS_C_MECH_CODE, 26 | GSS_C_NO_OID, 27 | message_context, 28 | status_string); 29 | 30 | /* if we do not have a matching saved error code 31 | * try to see if we can come up with one from the 32 | * mechglue by re-entering it. 33 | * We do not spcify the mech in this case it's not used by 34 | * the mechglue anyways */ 35 | if (maj == GSS_S_UNAVAILABLE) { 36 | 37 | return gss_display_status(minor_status, 38 | val, 39 | GSS_C_MECH_CODE, 40 | GSS_C_NO_OID, 41 | message_context, 42 | status_string); 43 | } 44 | 45 | *minor_status = min; 46 | return maj; 47 | } 48 | -------------------------------------------------------------------------------- /external/platform.m4: -------------------------------------------------------------------------------- 1 | AC_ARG_WITH([os], 2 | [AC_HELP_STRING([--with-os=OS_TYPE], [Type of your operation system (fedora|redhat|suse|gentoo)])] 3 | ) 4 | osname="" 5 | if test x"$with_os" != x ; then 6 | if test x"$with_os" = xfedora || \ 7 | test x"$with_os" = xredhat || \ 8 | test x"$with_os" = xsuse || \ 9 | test x"$with_os" = xgentoo || \ 10 | test x"$with_os" = xdebian ; then 11 | osname=$with_os 12 | else 13 | AC_MSG_ERROR([Illegal value -$with_os- for option --with-os]) 14 | fi 15 | fi 16 | 17 | if test x"$osname" = x ; then 18 | if test -f /etc/fedora-release ; then 19 | osname="fedora" 20 | elif test -f /etc/redhat-release ; then 21 | osname="redhat" 22 | elif test -f /etc/SuSE-release ; then 23 | osname="suse" 24 | elif test -f /etc/debian_version ; then 25 | osname="debian" 26 | elif test -f /etc/gentoo-release ; then 27 | osname="gentoo" 28 | fi 29 | 30 | AC_MSG_NOTICE([Detected operating system type: $osname]) 31 | fi 32 | 33 | AM_CONDITIONAL([HAVE_FEDORA], [test x"$osname" = xfedora]) 34 | AM_CONDITIONAL([HAVE_REDHAT], [test x"$osname" = xredhat]) 35 | AM_CONDITIONAL([HAVE_SUSE], [test x"$osname" = xsuse]) 36 | AM_CONDITIONAL([HAVE_DEBIAN], [test x"$osname" = xdebian]) 37 | AM_CONDITIONAL([HAVE_GENTOO], [test x"$osname" = xgentoo]) 38 | 39 | AC_CHECK_MEMBERS([struct ucred.pid, struct ucred.uid, struct ucred.gid], , , 40 | [[#include ]]) 41 | 42 | if test x"$ac_cv_member_struct_ucred_pid" = xyes -a \ 43 | x"$ac_cv_member_struct_ucred_uid" = xyes -a \ 44 | x"$ac_cv_member_struct_ucred_gid" = xyes ; then 45 | AC_DEFINE([HAVE_UCRED], [1], [Define if struct ucred is available]) 46 | else 47 | AC_MSG_ERROR([struct ucred is not available]) 48 | fi 49 | -------------------------------------------------------------------------------- /tests/t_program.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # Copyright (C) 2017 - GSS-Proxy contributors; see COPYING for the license. 3 | 4 | from testlib import * 5 | 6 | from t_acquire import run as run_acquire_test 7 | 8 | import os 9 | import testlib 10 | 11 | GSSPROXY_PROGRAM = ''' 12 | [gssproxy] 13 | debug_level = 3 14 | 15 | [service/t_acquire] 16 | mechs = krb5 17 | cred_store = keytab:${GSSPROXY_KEYTAB} 18 | cred_store = client_keytab:${GSSPROXY_CLIENT_KEYTAB} 19 | trusted = yes 20 | euid = ${UIDNUMBER} 21 | allow_client_ccache_sync = yes 22 | program = ${PROGDIR}/t_acquire 23 | ''' 24 | 25 | def run(testdir, env, conf): 26 | conf['prefix'] = str(testlib.cmd_index) 27 | prefix = conf["prefix"] 28 | retval = 0 29 | 30 | print("Testing positive program name matching...", file=sys.stderr) 31 | sys.stderr.write(" ") 32 | conf["prefix"] = prefix + "_1" 33 | update_gssproxy_conf(testdir, conf["keysenv"], GSSPROXY_PROGRAM) 34 | gssproxy_reload(testdir, conf['gpid']) 35 | retval |= run_acquire_test(testdir, env, conf) 36 | 37 | print("Testing negative program name matching...", file=sys.stderr) 38 | sys.stderr.write(" ") 39 | conf["prefix"] = prefix + "_2" 40 | bad_progdir = GSSPROXY_PROGRAM.replace("${PROGDIR}", "//bad/path") 41 | update_gssproxy_conf(testdir, conf["keysenv"], bad_progdir) 42 | gssproxy_reload(testdir, conf['gpid']) 43 | retval |= run_acquire_test(testdir, env, conf, expected_failure=True) 44 | 45 | # be a good citizen and clean up after ourselves 46 | update_gssproxy_conf(testdir, conf["keysenv"], GSSPROXY_CONF_TEMPLATE) 47 | gssproxy_reload(testdir, conf['gpid']) 48 | 49 | print_return(retval, -1, "(%d) Program" % testlib.cmd_index, False) 50 | testlib.cmd_index += 1 51 | return retval 52 | 53 | if __name__ == "__main__": 54 | from runtests import runtests_main 55 | runtests_main(["t_program.py"]) 56 | -------------------------------------------------------------------------------- /src/gp_rpc_wrap_size_limit.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011,2012 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gp_rpc_process.h" 4 | #include 5 | 6 | int gp_wrap_size_limit(struct gp_call_ctx *gpcall UNUSED, 7 | union gp_rpc_arg *arg, 8 | union gp_rpc_res *res) 9 | { 10 | gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; 11 | struct gssx_arg_wrap_size_limit *wsla; 12 | struct gssx_res_wrap_size_limit *wslr; 13 | uint32_t ret_maj; 14 | uint32_t ret_min; 15 | int ret; 16 | int exp_ctx_type; 17 | OM_uint32 max_size; 18 | 19 | wsla = &arg->wrap_size_limit; 20 | wslr = &res->wrap_size_limit; 21 | 22 | GPRPCDEBUG(gssx_arg_wrap_size_limit, wsla); 23 | 24 | exp_ctx_type = gp_get_exported_context_type(&wsla->call_ctx); 25 | if (exp_ctx_type == -1) { 26 | ret_maj = GSS_S_FAILURE; 27 | ret_min = EINVAL; 28 | goto done; 29 | } 30 | 31 | ret_maj = gp_import_gssx_to_ctx_id(&ret_min, 0, 32 | &wsla->context_handle, 33 | &context_handle); 34 | if (ret_maj) { 35 | goto done; 36 | } 37 | 38 | ret_maj = gss_wrap_size_limit(&ret_min, 39 | context_handle, 40 | wsla->conf_req, 41 | wsla->qop_state, 42 | wsla->req_output_size, 43 | &max_size); 44 | if (ret_maj) { 45 | goto done; 46 | } 47 | 48 | wslr->max_input_size = max_size; 49 | 50 | ret_maj = GSS_S_COMPLETE; 51 | ret_min = 0; 52 | 53 | done: 54 | ret = gp_conv_status_to_gssx(ret_maj, ret_min, 55 | GSS_C_NO_OID, 56 | &wslr->status); 57 | GPRPCDEBUG(gssx_res_wrap_size_limit, wslr); 58 | return ret; 59 | } 60 | -------------------------------------------------------------------------------- /docs/Releases/v0.4.0.md: -------------------------------------------------------------------------------- 1 | ## Highlights 2 | 3 | 4 | - Added optional support for running GSS-Proxy as an unprivileged user 5 | - Uses new /etc/gss/mech.d configuration directory for gss mechanisms 6 | - Kernel related fixes 7 | - General bug fixing, many minor errors or incorrect behaviours have been corrected 8 | 9 | 10 | ## Detailed Changelog 11 | 12 | Günther Deschner (1): 13 | 14 | - Fix potential segfault in gssi_inquire_context(). 15 | 16 | 17 | Lukas Slebodnik (9): 18 | 19 | - BUILD: Fix building rpms 20 | - BUILD: Tests did not work from parallel directory 21 | - BUILD: Change ordering of invoking Makefiles 22 | - Suppress clang warning 23 | - Wrong coversion function was used 24 | - Use defined enum instead of constant 25 | - Fix memory leak 26 | - BUILD: Fix building with automake 1.15 27 | - Fix few build issues 28 | 29 | 30 | Simo Sorce (24): 31 | 32 | - Fix config token parsing. 33 | - Add support for dropping privileges 34 | - Add zero termination when the buffer is a string 35 | - Make name conversion more robust to failure 36 | - Add utility functions to read()/write() safely 37 | - Block parent process until child is initialized. 38 | - Properly cleanup mutex on failure. 39 | - Add cmdline option to override default socket 40 | - Add a test framework for gss-proxy 41 | - Zero out the outputs of display_name 42 | - Install gssproxy mechanism config in mech.d 43 | - Generalize GSS Display Status logger code 44 | - Log why acquiring credentials failed. 45 | - Do not open logfile multiple times 46 | - Prevent a backtrace when a subprocess is not found 47 | - Use different env vars bases for gssapi tests 48 | - Really use gss-proxy in tests 49 | - Fix cast error 50 | - Fix error in compiling without SELinux 51 | - Default to systemd initscript in rpm spec file 52 | - Fix variable replacement in non config files 53 | - Properly handle security contexts on error 54 | - Suppress exported_composite_name for the kernel 55 | - Release version 0.4.0 56 | 57 | 58 | -------------------------------------------------------------------------------- /docs/Releases/v0.6.0.md: -------------------------------------------------------------------------------- 1 | ## Highlights 2 | 3 | 4 | - Test suite improvements 5 | - Improved tracing and debugging 6 | - s4u2proxy and s4u2self controls 7 | - Misc. leak fixes 8 | 9 | 10 | ## Detailed Changelog 11 | Robbie Harwood (24): 12 | 13 | - Deploy KDC on LDAP instead of db2 14 | - Package runtests.py in dist tarball 15 | - Add configure option for build hardening 16 | - Fix NULL deref in gssi_release_name() 17 | - Fix NULL deref in gssi_release_cred() 18 | - Fix type of argument to gppint_get_def_creds() 19 | - Appease clang with memset instead of initializer 20 | - Fix two leaks in gp_get_cred_environment() 21 | - Fix leak of localname in gp_export_creds_linux() 22 | - Fix leak of ach in gp_accept_sec_context() 23 | - Remove sysvinit support 24 | - Cause `make check` to behave as expected 25 | - Split out test library functions 26 | - Split out each test into its own file 27 | - Separate out test return checking logic 28 | - Indent subtests 29 | - Lower 30-second timeouts to 10 30 | - Add test for cred store extensions 31 | - Include new tests in `make dist` tarball 32 | - Default to a MEMORY cred_store ccache 33 | - Exercise default ccache behavior in test suite 34 | - Sync package spec file with fedora 35 | - Raise failures in test suite 36 | - Release version 0.6.0 37 | 38 | 39 | Simo Sorce (15): 40 | 41 | - Add cred_store support for local calls. 42 | - Make sure to pass on request for delegated creds 43 | - In acquire_cred_from, probe for remote creds 44 | - Always initialize ccache when storing. 45 | - Trace the gssproxy process too. 46 | - Improved debug options 47 | - Fix print_return logic 48 | - Use a local keytab for creds encryption 49 | - Parse cred_store struct earlier 50 | - Make local call static 51 | - Add control to permit/deny protocol transition 52 | - Control access to constrained delegation 53 | - Add more impersonation tests 54 | - Fix impersonation tests to work properly 55 | - Fix make distcheck 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/gp_log.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2012 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "config.h" 4 | #include "gp_log.h" 5 | #include 6 | #include 7 | 8 | /* global logging switch */ 9 | bool gp_syslog_status = false; 10 | 11 | void gp_logging_init(void) 12 | { 13 | openlog("gssproxy", 14 | LOG_CONS|LOG_NDELAY|LOG_NOWAIT|LOG_PERROR|LOG_PID, 15 | LOG_AUTHPRIV); 16 | } 17 | static size_t gp_append(char *buf, size_t max, const char *fmt, ...) 18 | { 19 | va_list ap; 20 | size_t res; 21 | 22 | if (max <= 0) return 0; 23 | 24 | va_start(ap, fmt); 25 | res = vsnprintf(buf, max, fmt, ap); 26 | va_end(ap); 27 | 28 | return res; 29 | } 30 | 31 | void gp_fmt_status(gss_OID mech, uint32_t maj, uint32_t min, 32 | char *buf, size_t buf_size) 33 | { 34 | uint32_t msgctx; 35 | uint32_t discard; 36 | gss_buffer_desc tmp; 37 | size_t used = 0; 38 | 39 | if (mech != GSS_C_NO_OID) { 40 | gss_oid_to_str(&discard, mech, &tmp); 41 | used += gp_append(buf + used, buf_size - used, 42 | "(OID: %s) ", (char *)tmp.value); 43 | gss_release_buffer(&discard, &tmp); 44 | } 45 | 46 | msgctx = 0; 47 | gss_display_status(&discard, maj, GSS_C_GSS_CODE, mech, &msgctx, &tmp); 48 | used += gp_append(buf + used, buf_size - used, "%s, ", (char *)tmp.value); 49 | gss_release_buffer(&discard, &tmp); 50 | 51 | msgctx = 0; 52 | gss_display_status(&discard, min, GSS_C_MECH_CODE, mech, &msgctx, &tmp); 53 | used += gp_append(buf + used, buf_size - used, "%s", (char *)tmp.value); 54 | gss_release_buffer(&discard, &tmp); 55 | } 56 | 57 | void gp_log_status(gss_OID mech, uint32_t maj, uint32_t min) 58 | { 59 | char buf[MAX_LOG_LINE]; 60 | 61 | if (!gp_syslog_status) 62 | return; 63 | 64 | gp_fmt_status(mech, maj, min, buf, MAX_LOG_LINE); 65 | syslog(LOG_DEBUG, "%s\n", buf); 66 | } 67 | -------------------------------------------------------------------------------- /docs/network_fs_clients.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Following changes to cifs.upcall, extending its functionality to leverage gssapi for ticket acquisition, 99-nfs-client.conf has been renamed to 99-network-fs-clients.conf. This allows the upcall programs for client side NFS and SMB, rpc.gssd and cifs.upcall, to leverage the same configuration file. However, there may be circumstances where having differentiated access for each remote filesystem is preferred or even necessary. 4 | 5 | ## Creating configuration files 6 | 7 | If different behavior for client side NFS and SMB is needed: 8 | 9 | 1) Remove /etc/gssproxy/99-network-fs-clients.conf 10 | 11 | 2) Create configuration files for cifs-client and nfs-client services. The `program =` option **must** be included if both programs are going to access the default socket, `/var/lib/gssproxy/default.sock` 12 | 13 | ~~~~ 14 | # cat /etc/gssproxy/99-cifs-client.conf 15 | [service/cifs-client] 16 | mechs = krb5 17 | cred_store = keytab:/etc/krb5.keytab 18 | cred_store = ccache:FILE:/var/lib/gssproxy/clients/krb5cc_%U 19 | cred_store = client_keytab:/var/lib/gssproxy/clients/%U.keytab 20 | cred_usage = initiate 21 | allow_any_uid = yes 22 | trusted = yes 23 | euid = 0 24 | program = /usr/sbin/cifs.upcall 25 | ~~~~ 26 | 27 | ~~~~ 28 | [service/nfs-client] 29 | mechs = krb5 30 | cred_store = keytab:/etc/krb5.keytab 31 | cred_store = ccache:FILE:/var/lib/gssproxy/clients/krb5cc_%U 32 | cred_store = client_keytab:/var/lib/gssproxy/clients/%U.keytab 33 | cred_usage = initiate 34 | allow_any_uid = yes 35 | trusted = yes 36 | euid = 0 37 | program = /usr/sbin/rpc.gssd 38 | ~~~~ 39 | 40 | 3) Customize the above files as needed. The existing docs/NFS.md file discusses Keytab based Client initiation as well as User Impersonation and Constrainted Delegation. Resource Base Constrained Delegation is also possible and requires no additional client side configuration changes as RBCD is a server side configuration change. 41 | -------------------------------------------------------------------------------- /src/client/gpm_wrap_size_limit.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011,2012 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gssapi_gpm.h" 4 | #include "src/gp_conv.h" 5 | 6 | OM_uint32 gpm_wrap_size_limit(OM_uint32 *minor_status, 7 | gssx_ctx *context_handle, 8 | int conf_req, 9 | gss_qop_t qop_req, 10 | OM_uint32 size_req, 11 | OM_uint32 *max_size) 12 | { 13 | union gp_rpc_arg uarg; 14 | union gp_rpc_res ures; 15 | gssx_arg_wrap_size_limit *arg = &uarg.wrap_size_limit; 16 | gssx_res_wrap_size_limit *res = &ures.wrap_size_limit; 17 | uint32_t ret_min = 0; 18 | uint32_t ret_maj = 0; 19 | int ret = 0; 20 | 21 | memset(&uarg, 0, sizeof(union gp_rpc_arg)); 22 | memset(&ures, 0, sizeof(union gp_rpc_res)); 23 | 24 | if (!context_handle) { 25 | return GSS_S_CALL_INACCESSIBLE_READ; 26 | } 27 | 28 | /* format request */ 29 | arg->context_handle = *context_handle; 30 | arg->conf_req = conf_req; 31 | arg->qop_state = qop_req; 32 | arg->req_output_size = size_req; 33 | 34 | /* execute proxy request */ 35 | ret = gpm_make_call(GSSX_WRAP_SIZE_LIMIT, &uarg, &ures); 36 | if (ret) { 37 | ret_maj = GSS_S_FAILURE; 38 | ret_min = ret; 39 | goto done; 40 | } 41 | 42 | /* format reply */ 43 | if (res->status.major_status) { 44 | gpm_save_status(&res->status); 45 | ret_min = res->status.minor_status; 46 | ret_maj = res->status.major_status; 47 | goto done; 48 | } 49 | 50 | if (max_size) { 51 | *max_size = res->max_input_size; 52 | } 53 | 54 | done: 55 | /* prevent the context handle from being destroyed in gpm_free_xdrs */ 56 | memset(&arg->context_handle, 0, sizeof(gssx_ctx)); 57 | 58 | gpm_free_xdrs(GSSX_WRAP_SIZE_LIMIT, &uarg, &ures); 59 | *minor_status = ret_min; 60 | return ret_maj; 61 | } 62 | -------------------------------------------------------------------------------- /docs/Releases/v0.2.0.md: -------------------------------------------------------------------------------- 1 | # Highlights 2 | 3 | - Switch to use cred store configuration options 4 | - Use the Credential Store and the Keytab Initiation features of Krb5 1.11 to handle trusted services 5 | 6 | 7 | 8 | # Detailed Changelog 9 | Günther Deschner (11): 10 | 11 | - Fix memory leak in gp_service_free(). 12 | - Silence a configure warning by adding AM_PROG_AR. 13 | - When checking for gssrpc libs also add gssapi library paths. 14 | - Add --all option to interposetest 15 | - Fix potential double-frees in load_services(). 16 | - Add gp_config_get_string_array() and an implementation in dinglibs backend. 17 | - Use mutivalued "cred_store" parameter, deprecate unused parameters. 18 | - Convert gp_config_get_* to return an error. 19 | - Add documentation for -d!|--debug in gssproxy manpage. 20 | - Add more documentation in the gssproxy.conf manpage. 21 | - Add new gssproxy-mech.8 manpage to describe the interposer plugin 22 | 23 | 24 | Simo Sorce (18): 25 | 26 | - Release 0.1.1 27 | - Replace deprecated libtool macros 28 | - Import names as remote name by default. 29 | - Add krb5_client_keytab config option 30 | - Carefully process desired name based on service 31 | - Move string formatting in a separate function 32 | - Add generic function to get creds defaults 33 | - Use new GSSAPI Credential Store API 34 | - Special case client_keytab for root user 35 | - Treat credential store as opaquely as possible. 36 | - Improve default configuration. 37 | - Add support for per-service sockets 38 | - Make config functions return actual error codes. 39 | - Use const string in config functions 40 | - Fix typo in gssproxy.8 manpage 41 | - Require nothing less than MIT krb5 1.11.2 42 | - Add gssproxy-mech.8 manpage to spec file 43 | - Bump version for 0.2.0 release 44 | 45 | 46 | 47 | # Note 48 | In order to use all features of this release MIt Krb5 1.11.2 is the minimum required.[[BR]] 49 | Additionally a [patch](https://github.com/krb5/krb5/commit/38cc076579888695a5820ceb44fe43020f5b61e1) only available in the development branch and targeted to 1.12 is required 50 | 51 | -------------------------------------------------------------------------------- /NOTES: -------------------------------------------------------------------------------- 1 | 2 | - How to handle mixed proxied and non-proxied credentials for one 3 | process? 4 | 5 | Idea #0: Always use the proxy or no proxy. Period. Use an env var to 6 | select mechglue config. 7 | 8 | Idea #1: Some mechglue magic and minor constraints on the applications. 9 | 10 | - mechglue needs to allow multiple providers to provide same 11 | mechanisms, with GSS_Acquire/Add_cred*() trying all providers for 12 | the desired mechanism(s) in order till one works or all fail; 13 | 14 | - this does not work for GSS_Init/Accept_sec_context() when using 15 | the default credential; 16 | 17 | - for GSS_Init_sec_context() just pick one provider to be first 18 | for default credential and let apps that want the other 19 | provider acquire a credential handle instead of using the 20 | default one (e.g., ssh -o GSSAPIInitiatorCredential=...); 21 | 22 | - for GSS_Accept_sec_context() declare that all acceptor 23 | credentials for any given mechanism must be proxied or not; 24 | 25 | Idea #2: Use PGSS or GSS-APIv3 so we can have a caller context handle 26 | via which to specify mechglue configuration. 27 | 28 | - SPNEGO (any pseudo-mechanism) should not be proxied, as it will 29 | re-enter the mechglue and call the proxy(ies) if needed (or not) as 30 | appropriate. 31 | 32 | 33 | - How to pass around ccaches ? 34 | We simply don't. 35 | 1. For a user, we should probably deny init_sec_context initially, but if we 36 | allow it we need to create a ccache like 37 | /var/lib/gssproxy/cc/krb5cc_ 38 | The user will not have direct access to the cache. 39 | 2. For a normal service we will do the same, both accept and init contetx use 40 | the configured keytab and the ccache will be in 41 | /var/lib/gssproxy/cc/krb5cc_ 42 | 3. For a trusted service we do the same as in 2. except when the service 43 | asks us to init_sec_context as a user, in that case we will try to use the 44 | user's ccache in /run/user//krb5cc, erroring out if it does not 45 | exist or is expired. 46 | -------------------------------------------------------------------------------- /src/gp_rpc_creds.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #ifndef _GP_RPC_CREDS_H_ 4 | #define _GP_RPC_CREDS_H_ 5 | 6 | #include "config.h" 7 | #include 8 | #include 9 | 10 | struct gp_call_ctx; 11 | 12 | bool gp_creds_allowed_mech(struct gp_call_ctx *gpcall, gss_OID desired_mech); 13 | uint32_t gp_get_supported_mechs(uint32_t *min, gss_OID_set *set); 14 | 15 | struct gssx_arg_acquire_cred; 16 | enum gp_aqcuire_cred_type { 17 | ACQ_NORMAL = 0, 18 | ACQ_IMPNAME = 1, 19 | }; 20 | int gp_get_acquire_type(struct gssx_arg_acquire_cred *arg); 21 | 22 | uint32_t gp_add_krb5_creds(uint32_t *min, 23 | struct gp_call_ctx *gpcall, 24 | enum gp_aqcuire_cred_type acquire_type, 25 | gss_cred_id_t in_cred, 26 | gssx_name *desired_name, 27 | gss_cred_usage_t cred_usage, 28 | uint32_t initiator_time_req, 29 | uint32_t acceptor_time_req, 30 | gss_cred_id_t *output_cred_handle, 31 | gss_OID_set *actual_mechs, 32 | uint32_t *initiator_time_rec, 33 | uint32_t *acceptor_time_rec); 34 | 35 | uint32_t gp_cred_allowed(uint32_t *min, 36 | struct gp_call_ctx *gpcall, 37 | gss_cred_id_t cred, 38 | gss_name_t target_name); 39 | 40 | void gp_filter_flags(struct gp_call_ctx *gpcall, uint32_t *flags); 41 | 42 | struct gp_cred_check_handle { 43 | struct gp_call_ctx *ctx; 44 | struct { 45 | u_int options_len; 46 | gssx_option *options_val; 47 | } options; 48 | }; 49 | uint32_t gp_check_sync_creds(struct gp_cred_check_handle *h, 50 | gss_cred_id_t cred); 51 | uint32_t gp_export_sync_creds(uint32_t *min, struct gp_call_ctx *gpcall, 52 | gss_cred_id_t *cred, 53 | gssx_option **options_val, u_int *options_len); 54 | 55 | #endif /* _GP_RPC_CREDS_H_ */ 56 | -------------------------------------------------------------------------------- /tests/t_accept.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "t_utils.h" 4 | 5 | int main(int argc, const char *argv[]) 6 | { 7 | char buffer[MAX_RPC_SIZE]; 8 | uint32_t buflen; 9 | gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; 10 | gss_buffer_desc in_token = GSS_C_EMPTY_BUFFER; 11 | gss_buffer_desc out_token = GSS_C_EMPTY_BUFFER; 12 | gss_name_t src_name = GSS_C_NO_NAME; 13 | uint32_t ret_maj; 14 | uint32_t ret_min; 15 | int ret = -1; 16 | 17 | /* We get stuff from stdin and spit it out on stderr */ 18 | ret = t_recv_buffer(STDIN_FD, buffer, &buflen); 19 | if (ret != 0) { 20 | DEBUG("Failed to read token from STDIN\n"); 21 | ret = -1; 22 | goto done; 23 | } 24 | 25 | in_token.value = buffer; 26 | in_token.length = buflen; 27 | 28 | ret_maj = gss_accept_sec_context(&ret_min, 29 | &context_handle, 30 | GSS_C_NO_CREDENTIAL, 31 | &in_token, 32 | GSS_C_NO_CHANNEL_BINDINGS, 33 | &src_name, 34 | NULL, 35 | &out_token, 36 | NULL, 37 | NULL, 38 | NULL); 39 | if (ret_maj) { 40 | DEBUG("Error accepting context\n"); 41 | t_log_failure(GSS_C_NO_OID, ret_maj, ret_min); 42 | ret = -1; 43 | goto done; 44 | } 45 | 46 | if (!out_token.length) { 47 | DEBUG("No output token ?"); 48 | ret = -1; 49 | goto done; 50 | } 51 | 52 | ret = t_send_buffer(STDOUT_FD, out_token.value, out_token.length); 53 | if (ret) { 54 | DEBUG("Failed to send data to client!\n"); 55 | ret = -1; 56 | goto done; 57 | } 58 | 59 | ret = 0; 60 | 61 | done: 62 | gss_delete_sec_context(&ret_min, &context_handle, NULL); 63 | gss_release_buffer(&ret_min, &out_token); 64 | gss_release_name(&ret_min, &src_name); 65 | return ret; 66 | } 67 | -------------------------------------------------------------------------------- /tests/t_reloading.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # Copyright (C) 2014,2015,2016 - GSS-Proxy contributors; see COPYING for the license 3 | 4 | from testlib import * 5 | from t_basic import run as run_basic_test 6 | 7 | def run(testdir, env, basicconf): 8 | basicconf['prefix'] = str(cmd_index) 9 | prefix = basicconf['prefix'] 10 | keysenv = basicconf["keysenv"] 11 | 12 | rets = [] 13 | 14 | print("Testing basic SIGHUP with no change", file=sys.stderr) 15 | sys.stderr.write(" ") 16 | basicconf['prefix'] += prefix + "_1" 17 | gssproxy_reload(testdir, basicconf['gpid']) 18 | r = run_basic_test(testdir, env, basicconf) 19 | rets.append(r) 20 | 21 | print("Testing SIGHUP with dropped service", file=sys.stderr) 22 | sys.stderr.write(" ") 23 | basicconf['prefix'] = prefix + "_2" 24 | update_gssproxy_conf(testdir, keysenv, GSSPROXY_CONF_MINIMAL_TEMPLATE) 25 | gssproxy_reload(testdir, basicconf['gpid']) 26 | r = run_basic_test(testdir, env, basicconf, True) 27 | rets.append(r) 28 | 29 | print("Testing SIGHUP with new service", file=sys.stderr) 30 | sys.stderr.write(" ") 31 | basicconf['prefix'] = prefix + "_3" 32 | update_gssproxy_conf(testdir, keysenv, GSSPROXY_CONF_TEMPLATE) 33 | gssproxy_reload(testdir, basicconf['gpid']) 34 | r = run_basic_test(testdir, env, basicconf) 35 | rets.append(r) 36 | 37 | print("Testing SIGHUP with change of socket", file=sys.stderr) 38 | sys.stderr.write(" ") 39 | basicconf['prefix'] = prefix + "_4" 40 | update_gssproxy_conf(testdir, keysenv, GSSPROXY_CONF_SOCKET_TEMPLATE) 41 | env['GSSPROXY_SOCKET'] += "2" 42 | gssproxy_reload(testdir, basicconf['gpid']) 43 | r = run_basic_test(testdir, env, basicconf) 44 | rets.append(r) 45 | 46 | # restore old configuration 47 | env['GSSPROXY_SOCKET'] = env['GSSPROXY_SOCKET'][:-1] 48 | update_gssproxy_conf(testdir, keysenv, GSSPROXY_CONF_TEMPLATE) 49 | gssproxy_reload(testdir, basicconf['gpid']) 50 | 51 | e = [r for r in rets if r != 0] 52 | if len(e) > 0: 53 | return e[0] 54 | return 0 55 | 56 | if __name__ == "__main__": 57 | from runtests import runtests_main 58 | runtests_main(["t_reloading.py"]) 59 | -------------------------------------------------------------------------------- /docs/KRB5_TRACE.md: -------------------------------------------------------------------------------- 1 | # Setting KRB5_TRACE for gssproxy 2 | 3 | This document explain how to obtain KRB5 tracing output. 4 | 5 | It is possible to get KRB5 tracing information together with gssproxy 6 | debugging information on Standard Error[^1] by simply running the 7 | process at debug level 3: `gssproxy -d --debug-level=3` 8 | 9 | In cases where it may be convenient to have a separate file with KRB5 10 | tracing it is possible to do so by making sure the KRB5_TRACE 11 | environment is set when the gssproxy process is executed[^2]. 12 | 13 | The output can be directed to any location, but gssproxy only has write 14 | access to `/var/lib/gssproxy` by default. This means that for a host 15 | system using SELinux either a custom module policy will need to be 16 | created or SELinux will need to be put into permissive mode. 17 | 18 | As setting `KRB5_TRACE` output is not designed to be used in production 19 | nor treated as traditional log output, it is recommended to direct the 20 | trace output to `/var/lib/gssproxy` to avoid changes to SELinux policy. 21 | 22 | Ways to obtain KRB5 tracing output: 23 | 24 | - Increase gssproxy debugging so that `KRB5_TRACE` information is logged 25 | as described in `# man gssproxy.conf`. 26 | 27 | ``` 28 | # echo ' debug_level = 3' >> /etc/gssproxy/gssproxy.conf 29 | # pkill -HUP gssproxy 30 | ``` 31 | 32 | - Create a systemd drop file for gssproxy to log `KRB5_TRACE` output 33 | ``` 34 | # mkdir /etc/systemd/system/gssproxy.service.d 35 | # cat < /etc/systemd/system/gssproxy.service.d/99-trace.conf 36 | [Service] 37 | Environment=KRB5_TRACE=/var/lib/gssproxy/gssproxy.krb5_trace 38 | EOF 39 | 40 | # systemctl daemon-reload 41 | # systemctl restart gssproxy 42 | ``` 43 | 44 | --- 45 | [^1]: Until recently, an [issue](https://github.com/gssapi/gssproxy/issues/44) 46 | with how the standard error is setup **required** redirection to an 47 | actual file in order to obtain any KRB5 Tracing information. If you are 48 | using an older version of gssproxy you will need to set the KRB5_TRACE 49 | environment variable to an actual file, changing debug level will not 50 | be sufficient. 51 | 52 | [^2]: Setting KRB5_TRACE will cause KRB5 tracing information to be 53 | emitted regradless of gssproxy's debug level. 54 | -------------------------------------------------------------------------------- /systemd/gssproxy.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=GSSAPI Proxy Daemon 3 | After=network.target 4 | Before=rpc-gssd.service 5 | 6 | [Service] 7 | ConfigurationDirectory=gssproxy 8 | StateDirectory=gssproxy gssproxy/clients gssproxy/rcache 9 | StateDirectoryMode=0700 10 | Environment=KRB5RCACHEDIR=/var/lib/gssproxy/rcache 11 | ExecStart=@sbindir@/gssproxy -i 12 | # This can be changed to notify-reload and ExecReload= can be removed once 13 | # systemd 253 is common enough 14 | Type=notify 15 | ExecReload=/bin/kill -HUP $MAINPID 16 | 17 | ProtectSystem=strict 18 | PrivateDevices=yes 19 | PrivateNetwork=yes 20 | PrivateIPC=yes 21 | # Blocks access to /home which may hold ccaches, also breaks euid mappings 22 | PrivateUsers=no 23 | # For now, read-writeable ccaches in /tmp, /root, /home and /run/user are 24 | # allowed, if you know that no such ccaches are used on your system, you might 25 | # want to override these defaults with a drop-in (see man systemd.unit(5)) 26 | # like this (stored in e.g. /etc/systemd/system/gssproxy.d/override.conf): 27 | # [Service] 28 | # PrivateTmp=yes 29 | # ProtectHome=tmpfs 30 | # ReadWritePaths= 31 | PrivateTmp=no 32 | ProtectHome=no 33 | ReadWritePaths=/root /home /run/user 34 | # Blocks propagation of hostname on change but when using a keytab, we want to 35 | # see hostname changes as the server will want to respond only for that name 36 | ProtectHostname=no 37 | ProtectClock=yes 38 | # Does *not* block rw access to /proc/net/rpc/use-gss-proxy 39 | ProtectKernelTunables=yes 40 | # Blocks access to /proc/net/rpc/use-gss-proxy and executable name matching 41 | ProtectProc=default 42 | ProtectKernelModules=yes 43 | ProtectKernelLogs=yes 44 | ProtectControlGroups=yes 45 | RestrictAddressFamilies=AF_UNIX AF_LOCAL 46 | RestrictNamespaces=yes 47 | LockPersonality=yes 48 | MemoryDenyWriteExecute=yes 49 | RestrictRealtime=yes 50 | RestrictSUIDSGID=yes 51 | PrivateMounts=yes 52 | # Stricter version: 53 | # SystemCallFilter=@default @basic-io @file-system @io-event @network-io @signal @ipc @process madvise umask uname 54 | SystemCallFilter=@system-service 55 | SystemCallErrorNumber=EPERM 56 | SystemCallArchitectures=native 57 | NoNewPrivileges=yes 58 | CapabilityBoundingSet=CAP_DAC_OVERRIDE 59 | IPAddressDeny=any 60 | UMask=0177 61 | 62 | [Install] 63 | WantedBy=multi-user.target 64 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | ci: 6 | name: CI 7 | runs-on: ubuntu-latest 8 | strategy: 9 | fail-fast: false 10 | matrix: 11 | name: [fedora, debian] 12 | compiler: [gcc, clang] 13 | include: 14 | - name: fedora 15 | container: fedora:latest 16 | - name: debian 17 | container: debian:sid 18 | container: ${{ matrix.container }} 19 | steps: 20 | - name: Install dependencies 21 | run: | 22 | if [ -f /etc/redhat-release ]; then 23 | dnf -y install --setopt='tsflags=' ${{ matrix.compiler }} \ 24 | make autoconf automake libtool pkgconf-pkg-config \ 25 | gettext-devel openssl-devel popt-devel docbook-style-xsl \ 26 | xml-common libxslt krb5-workstation krb5-devel \ 27 | libini_config-devel nss_wrapper socket_wrapper systemd-devel \ 28 | libselinux-devel libverto-devel python3 python3-colorama \ 29 | krb5-server krb5-server-ldap openldap-servers openldap-clients \ 30 | which valgrind 31 | elif [ -f /etc/debian_version ]; then 32 | apt-get -q update 33 | apt-get -yq install ${{ matrix.compiler }} make autoconf \ 34 | automake autotools-dev libtool pkg-config autopoint libssl-dev \ 35 | docbook-xsl docbook-xml libxml2-utils xml-core xsltproc \ 36 | libkrb5-dev libini-config-dev libkeyutils-dev libpopt-dev \ 37 | libselinux1-dev libsystemd-dev systemd-dev libverto-dev \ 38 | libnss-wrapper libsocket-wrapper python3 python3-colorama \ 39 | krb5-kdc krb5-admin-server krb5-kdc-ldap ldap-utils slapd \ 40 | valgrind 41 | fi 42 | - name: Checkout repository 43 | uses: actions/checkout@v4 44 | - name: Setup 45 | run: | 46 | autoreconf -fiv 47 | ./configure 48 | - name: Build and test 49 | env: 50 | CC: ${{ matrix.compiler }} 51 | run: make -s distcheck DISTCHECK_CONFIGURE_FLAGS="CC=\"$CC\"" 52 | - uses: actions/upload-artifact@v4 53 | if: failure() 54 | with: 55 | name: logs ${{ matrix.name }}, ${{ matrix.compiler }} 56 | path: | 57 | config.log 58 | testdir 59 | -------------------------------------------------------------------------------- /docs/Releases/v0.1.0.md: -------------------------------------------------------------------------------- 1 | # Highlights 2 | 3 | 4 | - Various critical fixes for the interposer plugin infrastructure 5 | - GSS-Proxy is now fully stateless through the use of new import/export credential functions avalable in MIT 1.11 6 | - Enable new kernel interface to enable GSS-Proxy support in the rpcgss kernel module (still not mainline) 7 | - Add environment variables to influence interposer plugin behavior. 8 | - Improved tests 9 | - Packaging fixes, including systemd unit files fixes 10 | 11 | 12 | # Detailed Changeog 13 | Andreas Schneider (1): 14 | 15 | - Packaging fixes 16 | 17 | 18 | Günther Deschner (16): 19 | 20 | - build: check for gss_import_cred and gss_export_cred. 21 | - Change interposer usage, clients need to set GSS_USE_PROXY=1|YES. 22 | - Add example GSS-API mechanism plugins config file. 23 | - interposer-plugin: Fix MIT 1.11 gssi_import_sec_context_by_mech symbol name. 24 | - mechglue: fix gssi_set_cred_option() arguments. 25 | - mechglue: initialize gpp cred_handle in gssi_acquire_cred_with_password(). 26 | - Add debug statement when gp_rpc_execute is called. 27 | - interpostest: improve debug output when gss_context_time() fails. 28 | - mechglue: add trace debugging 29 | - Fix gssi_import_sec_context_by_mech() 30 | - Fix gssi_context_time for remote calls. 31 | - Add various fixes to gssproxy.spec. 32 | - Add systemd packaging to gssproxy spec file. 33 | - Fix systemd config file for gssproxy. 34 | - Make it easier to test gssproxy behavior settings. 35 | - Test all possible proxy mode combinations. 36 | 37 | 38 | Simo Sorce (18): 39 | 40 | - Use new gss_import/export_cred functions 41 | - Move master version to 0.0.99 42 | - Fix includes 43 | - Add custom implementation of xdr_uint64_t 44 | - Use gssrpc instead of system rpc 45 | - Add support to get peer's SeLinux context 46 | - Remove gssproxy.service 47 | - Enable kernel support. 48 | - Make socket path a configure option 49 | - Write pid file at startup. 50 | - Create helper function to wrap token 51 | - Use token wrapper in gpp_remote_lo_local_ctx 52 | - Fix write_pid debug message 53 | - Improve ccache formatting. 54 | - Add helper function to check for krb5 oid 55 | - Add extension to set allowable enctypes 56 | - Add client side support to set allowed enctypes 57 | - Set version to 0.1 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/gp_conv.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #ifndef _GSS_CONV_H_ 4 | #define _GSS_CONV_H_ 5 | 6 | #include 7 | #include 8 | #include "rpcgen/gss_proxy.h" 9 | 10 | void *gp_memdup(void *in, size_t len); 11 | int gp_conv_octet_string(size_t length, void *value, octet_string *out); 12 | int gp_conv_octet_string_alloc(size_t length, void *value, 13 | octet_string **out); 14 | 15 | void gp_conv_gssx_to_oid(gssx_OID *in, gss_OID out); 16 | int gp_conv_gssx_to_oid_alloc(gssx_OID *in, gss_OID *out); 17 | int gp_conv_oid_to_gssx(gss_OID in, gssx_OID *out); 18 | int gp_conv_oid_to_gssx_alloc(gss_OID in, gssx_OID **out); 19 | 20 | void gp_conv_gssx_to_buffer(gssx_buffer *in, gss_buffer_t out); 21 | int gp_conv_gssx_to_buffer_alloc(gssx_buffer *in, gss_buffer_t *out); 22 | int gp_copy_gssx_to_buffer(gssx_buffer *in, gss_buffer_t out); 23 | int gp_copy_gssx_to_string_buffer(gssx_buffer *in, gss_buffer_t out); 24 | int gp_conv_buffer_to_gssx(gss_buffer_t in, gssx_buffer *out); 25 | int gp_conv_buffer_to_gssx_alloc(gss_buffer_t in, gssx_buffer **out); 26 | 27 | void gp_conv_gssx_to_cb(gssx_cb *in, gss_channel_bindings_t out); 28 | int gp_conv_cb_to_gssx(gss_channel_bindings_t in, gssx_cb *out); 29 | int gp_conv_cb_to_gssx_alloc(gss_channel_bindings_t in, gssx_cb **out); 30 | 31 | gssx_cred_usage gp_conv_cred_usage_to_gssx(gss_cred_usage_t in); 32 | gss_cred_usage_t gp_conv_gssx_to_cred_usage(gssx_cred_usage in); 33 | 34 | int gp_conv_err_to_gssx_string(uint32_t status, int type, gss_OID oid, 35 | utf8string *ret_str); 36 | 37 | uint32_t gp_conv_name_to_gssx(uint32_t *min, gss_name_t in, gssx_name *out); 38 | uint32_t gp_conv_name_to_gssx_alloc(uint32_t *min, 39 | gss_name_t in, gssx_name **out); 40 | uint32_t gp_conv_gssx_to_name(uint32_t *min, gssx_name *in, gss_name_t *out); 41 | 42 | int gp_conv_status_to_gssx(uint32_t ret_maj, uint32_t ret_min, 43 | gss_OID mech, struct gssx_status *status); 44 | 45 | int gp_copy_utf8string(utf8string *in, utf8string *out); 46 | int gp_copy_gssx_status_alloc(gssx_status *in, gssx_status **out); 47 | 48 | int gp_conv_gssx_to_oid_set(gssx_OID_set *in, gss_OID_set *out); 49 | int gp_conv_oid_set_to_gssx(gss_OID_set in, gssx_OID_set *out); 50 | 51 | int gp_copy_gssx_name(gssx_name *in, gssx_name *out); 52 | int gp_copy_gssx_name_alloc(gssx_name *in, gssx_name **out); 53 | 54 | #endif /* _GSS_CONV_H_ */ 55 | -------------------------------------------------------------------------------- /src/client/gpm_get_mic.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011,2012 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gssapi_gpm.h" 4 | #include "src/gp_conv.h" 5 | 6 | OM_uint32 gpm_get_mic(OM_uint32 *minor_status, 7 | gssx_ctx *context_handle, 8 | gss_qop_t qop_req, 9 | gss_buffer_t message_buffer, 10 | gss_buffer_t message_token) 11 | { 12 | union gp_rpc_arg uarg; 13 | union gp_rpc_res ures; 14 | gssx_arg_get_mic *arg = &uarg.get_mic; 15 | gssx_res_get_mic *res = &ures.get_mic; 16 | uint32_t ret_min = 0; 17 | uint32_t ret_maj = 0; 18 | int ret = 0; 19 | 20 | memset(&uarg, 0, sizeof(union gp_rpc_arg)); 21 | memset(&ures, 0, sizeof(union gp_rpc_res)); 22 | 23 | if (!context_handle) { 24 | return GSS_S_CALL_INACCESSIBLE_READ; 25 | } 26 | 27 | /* format request */ 28 | /* NOTE: the final free will also release the old context */ 29 | arg->context_handle = *context_handle; 30 | arg->qop_req = qop_req; 31 | ret = gp_conv_buffer_to_gssx(message_buffer, &arg->message_buffer); 32 | if (ret) { 33 | ret_maj = GSS_S_FAILURE; 34 | ret_min = ret; 35 | goto done; 36 | } 37 | 38 | /* execute proxy request */ 39 | ret = gpm_make_call(GSSX_GET_MIC, &uarg, &ures); 40 | if (ret) { 41 | ret_maj = GSS_S_FAILURE; 42 | ret_min = ret; 43 | goto done; 44 | } 45 | 46 | /* Check and save error status */ 47 | if (res->status.major_status) { 48 | gpm_save_status(&res->status); 49 | ret_min = res->status.minor_status; 50 | ret_maj = res->status.major_status; 51 | goto done; 52 | } 53 | 54 | ret = gp_copy_gssx_to_buffer(&res->token_buffer, message_token); 55 | if (ret) { 56 | ret_maj = GSS_S_FAILURE; 57 | ret_min = ret; 58 | goto done; 59 | } 60 | 61 | done: 62 | /* Steal the new context if available. 63 | * NOTE: We do not want it to be freed by xdr_free, so copy the contents 64 | * and cear up the structure to be freed so contents are not freed. */ 65 | if (res->context_handle) { 66 | *context_handle = *res->context_handle; 67 | memset(res->context_handle, 0, sizeof(gssx_ctx)); 68 | } else { 69 | /* prevent the contexthandle from being destroyed in case of server 70 | * error. */ 71 | memset(&arg->context_handle, 0, sizeof(gssx_ctx)); 72 | } 73 | 74 | gpm_free_xdrs(GSSX_GET_MIC, &uarg, &ures); 75 | *minor_status = ret_min; 76 | return ret_maj; 77 | } 78 | -------------------------------------------------------------------------------- /tests/t_multi_key.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # Copyright (C) 2014,2015,2016 - GSS-Proxy contributors; see COPYING for the license 3 | 4 | from t_basic import run as run_basic_test 5 | 6 | from testlib import * 7 | 8 | # Q: What are we testing here ? 9 | # 10 | # A: A client calling gss_init_sec_context() w/o explicitly acquiring 11 | # credentials before hand. [Note: in this case gssproxy uses the 'keytab' 12 | # specified in the store and ignores the 'client_keytab' one]. 13 | # 14 | # A gssproxy configruation where the keytab containes multiple keys, and a 15 | # krb5_principal option that sepcify what name we want to use. 16 | # 17 | # We try both names to make sure we target a specific key and not just pick up 18 | # the first in the keytab (which is the normal behavior). 19 | 20 | def run(testdir, env, conf): 21 | setup_multi_keys(testdir, env) 22 | conf['prefix'] = str(cmd_index) 23 | prefix = conf["prefix"] 24 | 25 | print("Testing multiple keys Keytab with first principal", 26 | file=sys.stderr) 27 | sys.stderr.write(" ") 28 | conf["prefix"] = prefix + "_1" 29 | if os.path.exists(os.path.join(testdir, 'gssproxy', 'gpccache')): 30 | os.unlink(os.path.join(testdir, 'gssproxy', 'gpccache')) 31 | p1env = {} 32 | p1env.update(conf["keysenv"]) 33 | p1env['client_name'] = MULTI_UPN 34 | p1env['KRB5_KTNAME'] = os.path.join(testdir, MULTI_KTNAME) 35 | update_gssproxy_conf(testdir, p1env, GSSPROXY_MULTI_TEMPLATE) 36 | gssproxy_reload(testdir, conf['gpid']) 37 | r1 = run_basic_test(testdir, env, conf) 38 | 39 | print("Testing multiple keys Keytab with second principal", 40 | file=sys.stderr) 41 | sys.stderr.write(" ") 42 | if os.path.exists(os.path.join(testdir, 'gssproxy', 'gpccache')): 43 | os.unlink(os.path.join(testdir, 'gssproxy', 'gpccache')) 44 | conf['prefix'] = prefix + "_2" 45 | p2env = {} 46 | p2env.update(conf["keysenv"]) 47 | p2env['client_name'] = MULTI_SVC 48 | p2env['KRB5_KTNAME'] = os.path.join(testdir, MULTI_KTNAME) 49 | update_gssproxy_conf(testdir, p2env, GSSPROXY_MULTI_TEMPLATE) 50 | gssproxy_reload(testdir, conf['gpid']) 51 | r2 = run_basic_test(testdir, env, conf) 52 | 53 | # Reset back gssproxy conf 54 | update_gssproxy_conf(testdir, conf["keysenv"], GSSPROXY_CONF_TEMPLATE) 55 | gssproxy_reload(testdir, conf['gpid']) 56 | 57 | if r1 != 0: 58 | return r1 59 | elif r2 != 0: 60 | return r2 61 | return 0 62 | 63 | if __name__ == "__main__": 64 | from runtests import runtests_main 65 | runtests_main(["t_multi_key.py"]) 66 | -------------------------------------------------------------------------------- /src/gp_rpc_verify_mic.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011,2012 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gp_rpc_process.h" 4 | #include 5 | 6 | int gp_verify_mic(struct gp_call_ctx *gpcall UNUSED, 7 | union gp_rpc_arg *arg, 8 | union gp_rpc_res *res) 9 | { 10 | gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; 11 | struct gssx_arg_verify_mic *vma; 12 | struct gssx_res_verify_mic *vmr; 13 | gss_buffer_desc message_buffer; 14 | gss_buffer_desc token_buffer; 15 | gss_qop_t qop_state; 16 | int exp_ctx_type; 17 | uint32_t ret_maj; 18 | uint32_t ret_min; 19 | int ret; 20 | 21 | vma = &arg->verify_mic; 22 | vmr = &res->verify_mic; 23 | 24 | GPRPCDEBUG(gssx_arg_verify_mic, vma); 25 | 26 | exp_ctx_type = gp_get_exported_context_type(&vma->call_ctx); 27 | if (exp_ctx_type == -1) { 28 | ret_maj = GSS_S_FAILURE; 29 | ret_min = EINVAL; 30 | goto done; 31 | } 32 | 33 | ret_maj = gp_import_gssx_to_ctx_id(&ret_min, 0, 34 | &vma->context_handle, 35 | &context_handle); 36 | if (ret_maj) { 37 | goto done; 38 | } 39 | 40 | gp_conv_gssx_to_buffer(&vma->message_buffer, &message_buffer); 41 | gp_conv_gssx_to_buffer(&vma->token_buffer, &token_buffer); 42 | 43 | ret_maj = gss_verify_mic(&ret_min, context_handle, 44 | &message_buffer, &token_buffer, 45 | &qop_state); 46 | if (ret_maj) { 47 | goto done; 48 | } 49 | 50 | vmr->context_handle = calloc(1, sizeof(gssx_ctx)); 51 | if (!vmr->context_handle) { 52 | ret_maj = GSS_S_FAILURE; 53 | ret_min = ENOMEM; 54 | goto done; 55 | } 56 | 57 | ret_maj = gp_export_ctx_id_to_gssx(&ret_min, exp_ctx_type, GSS_C_NO_OID, 58 | &context_handle, 59 | vmr->context_handle); 60 | if (ret_maj) { 61 | goto done; 62 | } 63 | 64 | vmr->qop_state = calloc(1, sizeof(gssx_qop)); 65 | if (!vmr->qop_state) { 66 | ret_maj = GSS_S_FAILURE; 67 | ret_min = ENOMEM; 68 | goto done; 69 | } 70 | 71 | *vmr->qop_state = qop_state; 72 | 73 | ret_maj = GSS_S_COMPLETE; 74 | ret_min = 0; 75 | 76 | done: 77 | ret = gp_conv_status_to_gssx(ret_maj, ret_min, 78 | GSS_C_NO_OID, 79 | &vmr->status); 80 | GPRPCDEBUG(gssx_res_verify_mic, vmr); 81 | return ret; 82 | } 83 | -------------------------------------------------------------------------------- /src/client/gpm_verify_mic.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011,2012 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gssapi_gpm.h" 4 | #include "src/gp_conv.h" 5 | 6 | OM_uint32 gpm_verify_mic(OM_uint32 *minor_status, 7 | gssx_ctx *context_handle, 8 | gss_buffer_t message_buffer, 9 | gss_buffer_t message_token, 10 | gss_qop_t *qop_state) 11 | { 12 | union gp_rpc_arg uarg; 13 | union gp_rpc_res ures; 14 | gssx_arg_verify_mic *arg = &uarg.verify_mic; 15 | gssx_res_verify_mic *res = &ures.verify_mic; 16 | uint32_t ret_min = 0; 17 | uint32_t ret_maj = 0; 18 | int ret = 0; 19 | 20 | memset(&uarg, 0, sizeof(union gp_rpc_arg)); 21 | memset(&ures, 0, sizeof(union gp_rpc_res)); 22 | 23 | if (!context_handle) { 24 | return GSS_S_CALL_INACCESSIBLE_READ; 25 | } 26 | 27 | /* format request */ 28 | /* NOTE: the final free will also release the old context */ 29 | arg->context_handle = *context_handle; 30 | ret = gp_conv_buffer_to_gssx(message_buffer, &arg->message_buffer); 31 | if (ret) { 32 | ret_maj = GSS_S_FAILURE; 33 | ret_min = ret; 34 | goto done; 35 | } 36 | ret = gp_conv_buffer_to_gssx(message_token, &arg->token_buffer); 37 | if (ret) { 38 | ret_maj = GSS_S_FAILURE; 39 | ret_min = ret; 40 | goto done; 41 | } 42 | 43 | /* execute proxy request */ 44 | ret = gpm_make_call(GSSX_VERIFY, &uarg, &ures); 45 | if (ret) { 46 | ret_maj = GSS_S_FAILURE; 47 | ret_min = ret; 48 | goto done; 49 | } 50 | 51 | /* Check and save error status */ 52 | if (res->status.major_status) { 53 | gpm_save_status(&res->status); 54 | ret_min = res->status.minor_status; 55 | ret_maj = res->status.major_status; 56 | goto done; 57 | } 58 | 59 | if (qop_state) { 60 | *qop_state = *res->qop_state; 61 | } 62 | 63 | done: 64 | /* Steal the new context if available. 65 | * NOTE: We do not want it to be freed by xdr_free, so copy the contents 66 | * and cear up the structure to be freed so contents are not freed. */ 67 | if (res->context_handle) { 68 | *context_handle = *res->context_handle; 69 | memset(res->context_handle, 0, sizeof(gssx_ctx)); 70 | } else { 71 | /* prevent the contexthandle from being destroyed in case of server 72 | * error. */ 73 | memset(&arg->context_handle, 0, sizeof(gssx_ctx)); 74 | } 75 | 76 | gpm_free_xdrs(GSSX_VERIFY, &uarg, &ures); 77 | *minor_status = ret_min; 78 | return ret_maj; 79 | } 80 | -------------------------------------------------------------------------------- /docs/Releases/v0.8.0.md: -------------------------------------------------------------------------------- 1 | Highlights: 2 | - Add capability to match services based on the name of the executable 3 | - Add support for reloading in our systemd unit file 4 | - Fix behavior with NFS setup 5 | 6 | Alexander Scheel (17): 7 | - Clarify test suite's logging 8 | - Create krb5 config files before setting up LDAP 9 | - Fix error reporting in init\_proc\_nfsd 10 | - Conditionally reload kernel interface on SIGHUP 11 | - Fix most memory leaks 12 | - Fix error handling in gp\_config\_from\_dir 13 | - Enable debugging for testsuites 14 | - Check for TERM in external environment before setting in tests 15 | - Update test and krb5 dependency list in BUILD.txt 16 | - [client] Switch to non-blocking sockets 17 | - [server] Add detailed request logging 18 | - Don't leak mech\_type when CONTINUE\_NEEDED from init\_sec\_context 19 | - Add call to verto\_cleanup() 20 | - Simplify setting NONBLOCK on socket 21 | - Fix handling of non-EPOLLIN/EPOLLOUT events 22 | - Fix error handling in gpm\_send\_buffer/gpm\_recv\_buffer 23 | - Fix silent crash with duplicate config sections 24 | 25 | Robbie Harwood (27): 26 | - Add mailing list and IRC links to README 27 | - Turn on -Wextra 28 | - Fix unused variables 29 | - Fix mismatched sign comparisons 30 | - Fix error checking on get\_impersonator\_fallback() 31 | - Remove gpm\_release\_ctx() to fix double unlock 32 | - Update systemd file 33 | - Mark selinux config attributes as deprecated 34 | - Require krb5 >= 1.14 for GSS\_KRB5\_CRED\_NO\_CI\_FLAGS\_X 35 | - Fix segfault when no config files are present 36 | - Include header for writev() 37 | - Make proc file failure loud but nonfatal 38 | - Appease gcc-7's fallthrough detection 39 | - Support matching based on executable name 40 | - Tolerate NULL pointers in gp\_same 41 | - Fix double free of popt context when querying version 42 | - Fix potential free of non-heap address 43 | - Prevent uninitialized read in error path of XDR contexts 44 | - Handle outdated encrypted ccaches 45 | - Update Apache docs to reflect config file split 46 | - Only empty FILE ccaches when storing remote creds 47 | - Fix a krb5 error code being returned as GSS major 48 | - Fix unused variable 49 | - Separate cred and ccache manipulation in gpp\_store\_remote\_creds() 50 | - Properly locate credentials in collection caches in mechglue 51 | - Properly initialize ccaches before storing into them 52 | - Update pagure release process 53 | 54 | Simo Sorce (8): 55 | - Properly renew expired credentials 56 | - Change impersonator check code 57 | - Allow connection to self when impersonator set 58 | - Add Client ID to debug messages 59 | - Fix memory leak 60 | - Style fixes 61 | - Emit debug on queue errors 62 | - Do not call gpm\_grab\_sock() twice 63 | -------------------------------------------------------------------------------- /docs/Releases/v0.5.0.md: -------------------------------------------------------------------------------- 1 | ## Highlights 2 | 3 | 4 | - Added support for config directory and config snippets and reload on SIGHUP 5 | - Improved debug logging/tracing 6 | - Actually implemented the docuemnted krb5_principal option 7 | - Numerous bugfixes 8 | 9 | 10 | ## Detailed Changelog 11 | 12 | Lukas Slebodnik (1): 13 | 14 | - BUILD: Include gp_rpc_debug.h into tarball 15 | 16 | 17 | Robbie Harwood (24): 18 | 19 | - Extract generalized selinux context comparison function 20 | - Ensure ini_config >= 1.2.0 for `ini_config_augment()` 21 | - Fix formatting on noncompliant copyright lines 22 | - Allow configdir and configfile to be specified together 23 | - getpwman(3) can return NULL without setting errno 24 | - Reload config on SIGHUP 25 | - Use pkg-config to find libgssapi-krb5.so* 26 | - Correct handling of EINTR on read()/write() 27 | - Port test suite to python3 28 | - Add tests for reloading on SIGHUP 29 | - Log useful message on kernel interface failure 30 | - Clear message structure before decoding into it 31 | - Fix potential deadlock on socket grab 32 | - Fix possible explicit NULL deref in gpm_accept_sec_context 33 | - Fix several leaks 34 | - Set C standard used to gnu99 35 | - Fix for gss_inquire_attrs_for_mech accepting NULLs 36 | - Specify KRB5RCACHEDIR in systemd unit file 37 | - Allow symbolic euids in conf files 38 | - Remove one layer of abstraction over dinglibs 39 | - Add support for config directories 40 | - Update man pages for symbolic euids and config snippets 41 | - Error on `allow_any_uid` issues 42 | - Add HTTP service and move NFS into its own conf file 43 | 44 | 45 | Roland Mainz (3): 46 | 47 | - Turn on strict aliasing rules 48 | - Remove support for iniparse library 49 | - Update BUILD.txt 50 | 51 | 52 | Simo Sorce (23): 53 | 54 | - Fix make clean 55 | - Fix const warning in gp_creds.c 56 | - Fix const warning that can lead to issues 57 | - Improve code in gp_export_gssx_cred() 58 | - Add options to specify a debug level 59 | - Add higher level debugging for all rpc calls 60 | - Add helper to find options in rpc messages 61 | - Add gss_acquire_cred_impersonate_name support 62 | - Add helpers to store and retrieve encrypted creds 63 | - Fix acquiring default credentials 64 | - Add acquire test and generally improve tests 65 | - Use t_utils.h in all tests. 66 | - Appropriately resolve const warnings in tests. 67 | - Add impersonate test 68 | - Better naming for tests log files 69 | - Always use valgrind for gssproxy tests 70 | - Since krb5 1.14 inquire_context may return no name 71 | - Fix crash bug when reconfiguring service 72 | - Fix use after free bug 73 | - Implement the krb5_principal option 74 | - Add test to verify krb5_principal works 75 | - Allow to specify a client name for init tests 76 | - Release version 0.5.0 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/gp_rpc_get_mic.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011,2012 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gp_rpc_process.h" 4 | #include 5 | 6 | int gp_get_mic(struct gp_call_ctx *gpcall UNUSED, 7 | union gp_rpc_arg *arg, 8 | union gp_rpc_res *res) 9 | { 10 | gss_buffer_desc message_buffer = GSS_C_EMPTY_BUFFER; 11 | gss_buffer_desc message_token = GSS_C_EMPTY_BUFFER; 12 | gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; 13 | struct gssx_arg_get_mic *gma; 14 | struct gssx_res_get_mic *gmr; 15 | uint32_t ret_maj; 16 | uint32_t ret_min; 17 | int ret; 18 | int exp_ctx_type; 19 | 20 | gma = &arg->get_mic; 21 | gmr = &res->get_mic; 22 | 23 | GPRPCDEBUG(gssx_arg_get_mic, gma); 24 | 25 | exp_ctx_type = gp_get_exported_context_type(&gma->call_ctx); 26 | if (exp_ctx_type == -1) { 27 | ret_maj = GSS_S_FAILURE; 28 | ret_min = EINVAL; 29 | goto done; 30 | } 31 | 32 | ret_maj = gp_import_gssx_to_ctx_id(&ret_min, 0, 33 | &gma->context_handle, 34 | &context_handle); 35 | if (ret_maj) { 36 | goto done; 37 | } 38 | 39 | gp_conv_gssx_to_buffer(&gma->message_buffer, &message_buffer); 40 | 41 | ret_maj = gss_get_mic(&ret_min, context_handle, 42 | gma->qop_req, &message_buffer, &message_token); 43 | if (ret_maj) { 44 | goto done; 45 | } 46 | 47 | gmr->context_handle = calloc(1, sizeof(gssx_ctx)); 48 | if (!gmr->context_handle) { 49 | ret_maj = GSS_S_FAILURE; 50 | ret_min = ENOMEM; 51 | goto done; 52 | } 53 | 54 | ret_maj = gp_export_ctx_id_to_gssx(&ret_min, exp_ctx_type, GSS_C_NO_OID, 55 | &context_handle, 56 | gmr->context_handle); 57 | if (ret_maj) { 58 | goto done; 59 | } 60 | 61 | gmr->qop_state = calloc(1, sizeof(gssx_qop)); 62 | if (!gmr->qop_state) { 63 | ret_maj = GSS_S_FAILURE; 64 | ret_min = ENOMEM; 65 | goto done; 66 | } 67 | 68 | /* what is the point of returning an input parameter ? - gd */ 69 | *gmr->qop_state = gma->qop_req; 70 | 71 | ret = gp_conv_buffer_to_gssx(&message_token, &gmr->token_buffer); 72 | if (ret) { 73 | ret_maj = GSS_S_FAILURE; 74 | ret_min = ret; 75 | goto done; 76 | } 77 | 78 | ret_maj = GSS_S_COMPLETE; 79 | ret_min = 0; 80 | 81 | done: 82 | ret = gp_conv_status_to_gssx(ret_maj, ret_min, 83 | GSS_C_NO_OID, &gmr->status); 84 | GPRPCDEBUG(gssx_res_get_mic, gmr); 85 | gss_release_buffer(&ret_min, &message_token); 86 | return ret; 87 | } 88 | -------------------------------------------------------------------------------- /src/client/gpm_inquire_context.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2012 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gssapi_gpm.h" 4 | 5 | OM_uint32 gpm_inquire_context(OM_uint32 *minor_status, 6 | gssx_ctx *context_handle, 7 | gssx_name **src_name, 8 | gssx_name **targ_name, 9 | OM_uint32 *lifetime_rec, 10 | gss_OID *mech_type, 11 | OM_uint32 *ctx_flags, 12 | int *locally_initiated, 13 | int *open) 14 | { 15 | OM_uint32 ret_maj; 16 | OM_uint32 tmp_min; 17 | int ret; 18 | 19 | if (!minor_status) { 20 | return GSS_S_CALL_INACCESSIBLE_WRITE; 21 | } 22 | *minor_status = 0; 23 | 24 | if (!context_handle) { 25 | return GSS_S_CALL_INACCESSIBLE_READ; 26 | } 27 | 28 | if (src_name) { 29 | ret_maj = gpm_duplicate_name(minor_status, 30 | &context_handle->src_name, 31 | src_name); 32 | if (ret_maj != GSS_S_COMPLETE) { 33 | return ret_maj; 34 | } 35 | } 36 | 37 | if (targ_name) { 38 | ret_maj = gpm_duplicate_name(minor_status, 39 | &context_handle->targ_name, 40 | targ_name); 41 | if (ret_maj != GSS_S_COMPLETE) { 42 | if (src_name) { 43 | (void)gpm_release_name(&tmp_min, src_name); 44 | } 45 | return ret_maj; 46 | } 47 | } 48 | 49 | if (lifetime_rec) { 50 | *lifetime_rec = (OM_uint32)context_handle->lifetime; 51 | } 52 | 53 | if (mech_type) { 54 | gss_OID_desc mech; 55 | gp_conv_gssx_to_oid(&context_handle->mech, &mech); 56 | ret = gpm_mech_to_static(&mech, mech_type); 57 | if (ret) { 58 | if (src_name) { 59 | (void)gpm_release_name(&tmp_min, src_name); 60 | } 61 | if (targ_name) { 62 | (void)gpm_release_name(&tmp_min, targ_name); 63 | } 64 | *minor_status = ret; 65 | return GSS_S_FAILURE; 66 | } 67 | } 68 | 69 | if (ctx_flags) { 70 | *ctx_flags = (OM_uint32)context_handle->ctx_flags; 71 | } 72 | 73 | if (locally_initiated) { 74 | if (context_handle->locally_initiated) { 75 | *locally_initiated = 1; 76 | } else { 77 | *locally_initiated = 0; 78 | } 79 | } 80 | 81 | if (open) { 82 | if (context_handle->open) { 83 | *open = 1; 84 | } else { 85 | *open = 0; 86 | } 87 | } 88 | 89 | return GSS_S_COMPLETE; 90 | } 91 | -------------------------------------------------------------------------------- /tests/t_utils.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "t_utils.h" 4 | #include 5 | #include 6 | #include 7 | 8 | int t_send_buffer(int fd, char *buf, uint32_t len) 9 | { 10 | uint32_t size; 11 | ssize_t wn; 12 | size_t pos; 13 | 14 | size = htonl(len); 15 | 16 | wn = write(fd, &size, sizeof(uint32_t)); 17 | if (wn != 4) { 18 | return EIO; 19 | } 20 | 21 | pos = 0; 22 | while (len > pos) { 23 | wn = write(fd, buf + pos, len - pos); 24 | if (wn == -1) { 25 | if (errno == EINTR) { 26 | continue; 27 | } 28 | return errno; 29 | } 30 | pos += wn; 31 | } 32 | 33 | return 0; 34 | } 35 | 36 | int t_recv_buffer(int fd, char *buf, uint32_t *len) 37 | { 38 | uint32_t size; 39 | ssize_t rn; 40 | size_t pos; 41 | 42 | rn = read(fd, &size, sizeof(uint32_t)); 43 | if (rn != 4) { 44 | return EIO; 45 | } 46 | 47 | *len = ntohl(size); 48 | 49 | if (*len > MAX_RPC_SIZE) { 50 | return EINVAL; 51 | } 52 | 53 | pos = 0; 54 | while (*len > pos) { 55 | rn = read(fd, buf + pos, *len - pos); 56 | if (rn == -1) { 57 | if (errno == EINTR) { 58 | continue; 59 | } 60 | return errno; 61 | } 62 | if (rn == 0) { 63 | return EIO; 64 | } 65 | pos += rn; 66 | } 67 | 68 | return 0; 69 | } 70 | 71 | void t_log_failure(gss_OID mech, uint32_t maj, uint32_t min) 72 | { 73 | uint32_t msgctx; 74 | uint32_t discard; 75 | gss_buffer_desc tmp; 76 | 77 | fprintf(stderr, "Failed with:"); 78 | 79 | if (mech != GSS_C_NO_OID) { 80 | gss_oid_to_str(&discard, mech, &tmp); 81 | fprintf(stderr, " (OID: %s)", (char *)tmp.value); 82 | gss_release_buffer(&discard, &tmp); 83 | } 84 | 85 | msgctx = 0; 86 | gss_display_status(&discard, maj, GSS_C_GSS_CODE, mech, &msgctx, &tmp); 87 | fprintf(stderr, " %s,", (char *)tmp.value); 88 | gss_release_buffer(&discard, &tmp); 89 | 90 | msgctx = 0; 91 | gss_display_status(&discard, min, GSS_C_MECH_CODE, mech, &msgctx, &tmp); 92 | fprintf(stderr, " %s\n", (char *)tmp.value); 93 | gss_release_buffer(&discard, &tmp); 94 | } 95 | 96 | int t_string_to_name(const char *string, gss_name_t *name, gss_OID type) 97 | { 98 | gss_buffer_desc target_buf; 99 | uint32_t ret_maj; 100 | uint32_t ret_min; 101 | 102 | target_buf.value = strdup(string); 103 | target_buf.length = strlen(string) + 1; 104 | 105 | ret_maj = gss_import_name(&ret_min, &target_buf, type, name); 106 | free(target_buf.value); 107 | return ret_maj; 108 | } 109 | -------------------------------------------------------------------------------- /tests/t_cred_store.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2016 the GSS-PROXY contributors; see COPYING for license */ 2 | 3 | #include "t_utils.h" 4 | #include 5 | 6 | int main(int argc, const char *argv[]) 7 | { 8 | uint32_t major, minor; 9 | gss_key_value_set_desc store = {}; 10 | int ret = -1; 11 | gss_cred_id_t cred_handle = GSS_C_NO_CREDENTIAL; 12 | gss_OID_set_desc oid_set = { 1, discard_const(gss_mech_krb5) }; 13 | 14 | if (argc != 3) { 15 | DEBUG("Usage: %s source_ccache dest_ccache\n", argv[0]); 16 | goto done; 17 | } 18 | 19 | store.elements = calloc(1, sizeof(struct gss_key_value_element_struct)); 20 | if (!store.elements) { 21 | DEBUG("calloc failed\n"); 22 | goto done; 23 | } 24 | store.count = 1; 25 | store.elements[0].key = "ccache"; 26 | 27 | /* Acquire initial cred handle from store */ 28 | store.elements[0].value = argv[1]; 29 | major = gss_acquire_cred_from(&minor, 30 | GSS_C_NO_NAME, 31 | GSS_C_INDEFINITE, 32 | &oid_set, 33 | GSS_C_INITIATE, 34 | &store, 35 | &cred_handle, 36 | NULL, 37 | NULL); 38 | if (major != GSS_S_COMPLETE) { 39 | DEBUG("gss_acquire_cred_from() failed\n"); 40 | t_log_failure(GSS_C_NO_OID, major, minor); 41 | goto done; 42 | } 43 | 44 | /* Test storing credentials */ 45 | store.elements[0].value = argv[2]; 46 | major = gss_store_cred_into(&minor, 47 | cred_handle, 48 | GSS_C_INITIATE, 49 | GSS_C_NO_OID, 50 | 1, 51 | 1, 52 | &store, 53 | NULL, 54 | NULL); 55 | if (major != GSS_S_COMPLETE) { 56 | DEBUG("gss_store_cred_into() failed\n"); 57 | t_log_failure(GSS_C_NO_OID, major, minor); 58 | goto done; 59 | } 60 | 61 | /* Test that we can actually manipulate the stored credentials */ 62 | gss_release_cred(&minor, &cred_handle); 63 | cred_handle = GSS_C_NO_CREDENTIAL; 64 | major = gss_acquire_cred_from(&minor, 65 | GSS_C_NO_NAME, 66 | GSS_C_INDEFINITE, 67 | &oid_set, 68 | GSS_C_INITIATE, 69 | &store, 70 | &cred_handle, 71 | NULL, 72 | NULL); 73 | if (major != GSS_S_COMPLETE) { 74 | DEBUG("second gss_acquire_cred_from() failed\n"); 75 | t_log_failure(GSS_C_NO_OID, major, minor); 76 | goto done; 77 | } 78 | 79 | ret = 0; 80 | done: 81 | if (store.elements) { 82 | free(store.elements); 83 | } 84 | gss_release_cred(&minor, &cred_handle); 85 | return ret; 86 | } 87 | -------------------------------------------------------------------------------- /docs/ProtocolDocumentation.md: -------------------------------------------------------------------------------- 1 | # GSS-PROXY Protocol Documentation 2 | 3 | The GSS-PROXY protocol is an RPC protocol based on ONCRPC v2. 4 | 5 | ## Protocol Definition 6 | 7 | The protocol definition file is currently maintained in GIT here: 8 | https://github.com/gssapi/gssproxy/blob/master/x-files/gss_proxy.x 9 | 10 | The protocol is not stable yet and it is being revised while we progress prototyping client and server code, however the parts used by the Linux kernel driver are considered final and will see no backward incompatible changes. 11 | 12 | Long term we will probably submit an actual RFC to the IETF to standardize it. 13 | 14 | ## Extensions 15 | 16 | There are 2 "extensions" currently being worked on for the Linux kernel client. 17 | 18 | ### Lucid context export type 19 | The Linux Kernel needs a special export and serialize Lucid context. 20 | 21 | To inform the proxy that this special format should be returned from the gss_accept_se_context call, the client needs to set a gssx_option in call_ctx structure. 22 | 23 | The option field is set to the string "exported_context_type" 24 | 25 | The value field is set to the string "linux_lucid_v1" 26 | 27 | When these fields are set the proxy will return a lucid context formatted accordingly to the Linux Kernel needs instead of a normal exported context buffer. 28 | 29 | ### Export credentials flag 30 | When the accept_sec_context call is completed the Linux Kernel needs to be given a credential set containing all the user uid, gid and secondary gids so that is can properly handle access control. 31 | 32 | To inform the proxy that this data is needed the clientneeds to set a gssx_option in call_ctx structure. 33 | 34 | The option field is set to the string "exported_creds_type" 35 | 36 | The value field is set to the string "linux_creds_v1" 37 | 38 | When these fields are set the proxy will return a buffer containing the credentials in the accpet_sec_context call response buffer as a gssx_option. 39 | 40 | The option field is set to the string "linux_creds_v1" 41 | 42 | The value field contains the creds buffer. 43 | 44 | This buffer is composed of the fixed fields of 32 bit size and an array of 32 bit values as follows: ` , , , ` 45 | 46 | ### Krb5 Set Allowed Enctypes 47 | Allows to send a krb5 mechanism specific option to set the allowed encryption types for a credential. 48 | 49 | When a client obtains valid credentials it can attach an option to a gssx_cred_element element of a gssx_cred credential to indicate to the server the desire to limit the allowed encryption types used on said credential before the following call. 50 | On the next call, when said credentials are transmitted to the Gss Proxy, the server will probe the received credentials and will attempt a call to gss_krb5_set_allowed_enctypes() using the data provided in the credentials received. 51 | 52 | The gssx_cred option should be placed in a gssx_cred_element whose mech type is one of the recognized krb5 mechanism OIDs. 53 | 54 | The option field is set to the string "krb5_set_allowed_enctype_values" 55 | 56 | The value field contains a buffer of 32bit integers 57 | 58 | The length of the buffer divided by 4 determines the number of enctypes conveyed. The array of integers is stored in machine dependent byte order, and is cast directly into an array of krb5_enctypes. 59 | 60 | 61 | -------------------------------------------------------------------------------- /docs/Userproxy.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | The GSS-Proxy hs been built for two purposes: to server the kernel NFSD and for 4 | privilege separation in userspace. 5 | 6 | The privilege separation feature has been used, so far, to allow unprivileged 7 | user processes to use keys (keytabs) that are held by root (or potentially a 8 | different user). 9 | 10 | However there is another case where privilege separation is useful, and that is 11 | usage of contained applications in a user session, for example using flatpaks, 12 | which are a containerized solution that aims, among other things, at 13 | constraining what apps within the flatpak can do and not give full unfettered 14 | access to the user session. 15 | 16 | Userproxy is tailored to this kind of use. 17 | 18 | NOTE: Do not donfuse the userproxy mode of operations with the run_as_user 19 | configure option, thes eare completely orthogonal things. 20 | 21 | NOTE: carefully read the Behavior section 22 | 23 | ## Setting up Userproxy mode 24 | 25 | If GSS-Proxy is started with the argument -u|--userproxy it switched to 26 | userproxy mode. This has some profound consequences on the behavior of 27 | GSS-Proxy. 28 | 29 | ### Configuration 30 | 31 | First of all the configuration file is completely ignored and not even parsed, 32 | instead a single-service configuration is synthetized that allows only 33 | processes from the same euid to connect to the proxy socket. The idea is to 34 | allow any operations the user may be normally doing, just bridging a confined 35 | user application to the main user session to avoid direct access to TGT but 36 | otherwise not restricting any use. 37 | 38 | ### Communication Socket 39 | 40 | The default Socket is changed to be in the user runtime directory: 41 | $XDG_RUNTIME_DIR/gssprosy/default.sock 42 | If the $XDG_RUNTIME_DIR environment variable is not set or the directory doe 43 | not exist, the proxy will fail to start. 44 | The 'gssproxy' directory will be created in $XDG_RUNTIME_DIR if it does not 45 | exists before opening the default.sock unix-socket file. 46 | 47 | The -s option can be used to provide a custom socket location, in this case the 48 | whole directory structure needs to be in place or startup will fail. 49 | 50 | ### Behavior 51 | 52 | Because this mode is intended to provide full access to a user session, 53 | including potentially further proxing out to another gssproxy instance, the 54 | userproxy mode does not prevent loops in GSSAPI by internally setting the 55 | GSS_USE_PROXY env var to "no", as the default mode does. 56 | 57 | This allows the following to work: 58 | [container (GSSAPI app)] -> [user session (GSS-Proxy)] -> [privileged 59 | (GSS-Proxy)] 60 | 61 | It is also the reason why a non standard socket is used in this mode, so that 62 | the proxymech plugin running withing GSSAPI in the GSS-Proxy's userproxy 63 | itself does not, in fact, try to reconnect back and deadlock in a loop. 64 | 65 | Within the container it is recommended to bind mount the userproxy created 66 | directory on the standard location which is generally: 67 | /var/lib/gssproxy 68 | 69 | Additionally in the container the USE_GSS_PROXY env var needs to be set to 70 | the value "yes" unless the proxymech.so pluging within the container has been 71 | built to always enable proxing. 72 | For example, a container may custom build the gss module plugin with: 73 | ./configure --enable-always-interpose \ 74 | --enable-only-gss-module 75 | -------------------------------------------------------------------------------- /src/gp_debug.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011,2018 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "config.h" 4 | #include 5 | #include 6 | #include "gp_proxy.h" 7 | #include "gp_debug.h" 8 | #include "gp_log.h" 9 | 10 | /* global debug switch */ 11 | int gp_debug = 0; 12 | 13 | 14 | void (*gp_debug_setup_k5_trace_fn)(int) = NULL; 15 | 16 | void gp_debug_set_krb5_tracing_fn(void (*fn)(int)) 17 | { 18 | if (gp_debug_setup_k5_trace_fn != NULL) { 19 | /* deactivate potential previously set tracing 20 | * facility */ 21 | gp_debug_setup_k5_trace_fn(0); 22 | } 23 | 24 | gp_debug_setup_k5_trace_fn = fn; 25 | 26 | /* the tracing setup function may be set after the 27 | * initial debug level is set via configuration. 28 | * Make sure to immedaiately call it if debug level is 29 | * already above 3 */ 30 | if (gp_debug >= 3 && !getenv("KRB5_TRACE")) { 31 | gp_debug_setup_k5_trace_fn(1); 32 | } 33 | } 34 | 35 | void gp_debug_toggle(int level) 36 | { 37 | if (level >= 3 && !getenv("KRB5_TRACE")) { 38 | if (gp_debug_setup_k5_trace_fn) { 39 | gp_debug_setup_k5_trace_fn(1); 40 | } else { 41 | setenv("KRB5_TRACE", "/dev/stderr", 1); 42 | } 43 | } else if (level < 3) { 44 | if (gp_debug_setup_k5_trace_fn) { 45 | gp_debug_setup_k5_trace_fn(0); 46 | } else { 47 | unsetenv("KRB5_TRACE"); 48 | } 49 | } 50 | 51 | gp_debug = level; 52 | GPDEBUG("Debug Level changed to %d\n", gp_debug); 53 | } 54 | 55 | void gp_log_failure(gss_OID mech, uint32_t maj, uint32_t min) 56 | { 57 | char buf[MAX_LOG_LINE]; 58 | 59 | gp_fmt_status(mech, maj, min, buf, MAX_LOG_LINE); 60 | 61 | fprintf(stderr, "Failed with: %s\n", buf); 62 | } 63 | 64 | const char *gp_debug_timestamp(void) 65 | { 66 | static __thread char buffer[24]; 67 | static __thread time_t timestamp = 0; 68 | struct tm tm_info; 69 | time_t now; 70 | 71 | time(&now); 72 | if (now == timestamp) return buffer; 73 | 74 | gmtime_r(&now, &tm_info); 75 | strftime(buffer, 24, "[%Y/%m/%d %H:%M:%S]: ", &tm_info); 76 | timestamp = now; 77 | return buffer; 78 | } 79 | 80 | /* thread local connection/client id */ 81 | static __thread int cid; 82 | 83 | void gp_debug_set_conn_id(int id) 84 | { 85 | cid = id; 86 | } 87 | 88 | static const char*gp_debug_conn_id(void) 89 | { 90 | static __thread char buffer[18]; 91 | static __thread int last_cid = 0; 92 | 93 | if (cid == 0) { 94 | buffer[0] = '\0'; 95 | return buffer; 96 | } 97 | 98 | if (last_cid == cid) return buffer; 99 | 100 | (void)snprintf(buffer, 17, "[CID %d]", cid); 101 | buffer[17] = '\0'; 102 | last_cid = cid; 103 | return buffer; 104 | } 105 | 106 | void gp_debug_printf(const char *format, ...) 107 | { 108 | va_list varargs; 109 | va_start(varargs, format); 110 | vfprintf(stderr, format, varargs); 111 | va_end(varargs); 112 | } 113 | 114 | void gp_debug_time_printf(const char *format, ...) 115 | { 116 | va_list varargs; 117 | 118 | fprintf(stderr, "%s%s", gp_debug_conn_id(), gp_debug_timestamp()); 119 | 120 | va_start(varargs, format); 121 | vfprintf(stderr, format, varargs); 122 | va_end(varargs); 123 | } 124 | -------------------------------------------------------------------------------- /src/gp_rpc_debug.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #ifndef _GP_RPC_DEBUG_H_ 4 | #define _GP_RPC_DEBUG_H_ 5 | 6 | #include "gp_debug.h" 7 | 8 | void gpdbg_utf8string(utf8string *x); 9 | void gpdbg_octet_string(octet_string *x); 10 | void gpdbg_gssx_uint64(gssx_uint64 *x); 11 | #define gpdbg_gssx_qop gpdbg_gssx_uint64 12 | #define gpdbg_gssx_buffer gpdbg_octet_string 13 | void gpdbg_gssx_OID(gssx_OID *x); 14 | void gpdbg_gssx_OID_set(gssx_OID_set *x); 15 | void gpdbg_gssx_cred_usage(gssx_cred_usage *x); 16 | #define gpdbg_gssx_time gpdbg_gssx_uint64 17 | void gpdbg_gssx_option(gssx_option *x); 18 | void gpdbg_gssx_mech_attr(gssx_mech_attr *x); 19 | void gpdbg_gssx_mech_info(gssx_mech_info *x); 20 | void gpdbg_gssx_name_attr(gssx_name_attr *x); 21 | void gpdbg_gssx_status(gssx_status *x); 22 | void gpdbg_gssx_call_ctx(gssx_call_ctx *x); 23 | void gpdbg_gssx_name(gssx_name *x); 24 | void gpdbg_gssx_cred_element(gssx_cred_element *x); 25 | void gpdbg_gssx_cred(gssx_cred *x); 26 | void gpdbg_gssx_ctx(gssx_ctx *x); 27 | void gpdbg_gssx_handle(gssx_handle *x); 28 | void gpdbg_gssx_cb(gssx_cb *x); 29 | 30 | void gpdbg_gssx_arg_release_handle(gssx_arg_release_handle *x); 31 | void gpdbg_gssx_res_release_handle(gssx_res_release_handle *x); 32 | void gpdbg_gssx_arg_indicate_mechs(gssx_arg_indicate_mechs *x); 33 | void gpdbg_gssx_res_indicate_mechs(gssx_res_indicate_mechs *x); 34 | void gpdbg_gssx_arg_import_and_canon_name(gssx_arg_import_and_canon_name *x); 35 | void gpdbg_gssx_res_import_and_canon_name(gssx_res_import_and_canon_name *x); 36 | void gpdbg_gssx_arg_get_call_context(gssx_arg_get_call_context *x); 37 | void gpdbg_gssx_res_get_call_context(gssx_res_get_call_context *x); 38 | void gpdbg_gssx_arg_acquire_cred(gssx_arg_acquire_cred *x); 39 | void gpdbg_gssx_res_acquire_cred(gssx_res_acquire_cred *x); 40 | void gpdbg_gssx_arg_export_cred(gssx_arg_export_cred *x); 41 | void gpdbg_gssx_res_export_cred(gssx_res_export_cred *x); 42 | void gpdbg_gssx_arg_import_cred(gssx_arg_import_cred *x); 43 | void gpdbg_gssx_res_import_cred(gssx_res_import_cred *x); 44 | void gpdbg_gssx_arg_store_cred(gssx_arg_store_cred *x); 45 | void gpdbg_gssx_res_store_cred(gssx_res_store_cred *x); 46 | void gpdbg_gssx_arg_init_sec_context(gssx_arg_init_sec_context *x); 47 | void gpdbg_gssx_res_init_sec_context(gssx_res_init_sec_context *x); 48 | void gpdbg_gssx_arg_accept_sec_context(gssx_arg_accept_sec_context *x); 49 | void gpdbg_gssx_res_accept_sec_context(gssx_res_accept_sec_context *x); 50 | void gpdbg_gssx_arg_get_mic(gssx_arg_get_mic *x); 51 | void gpdbg_gssx_res_get_mic(gssx_res_get_mic *x); 52 | void gpdbg_gssx_arg_verify_mic(gssx_arg_verify_mic *x); 53 | void gpdbg_gssx_res_verify_mic(gssx_res_verify_mic *x); 54 | void gpdbg_gssx_arg_wrap(gssx_arg_wrap *x); 55 | void gpdbg_gssx_res_wrap(gssx_res_wrap *x); 56 | void gpdbg_gssx_arg_unwrap(gssx_arg_unwrap *x); 57 | void gpdbg_gssx_res_unwrap(gssx_res_unwrap *x); 58 | void gpdbg_gssx_arg_wrap_size_limit(gssx_arg_wrap_size_limit *x); 59 | void gpdbg_gssx_res_wrap_size_limit(gssx_res_wrap_size_limit *x); 60 | 61 | #define GP_RPC_DEBUG_LVL 2 62 | #define GP_RPC_DEBUG_FULL 3 63 | 64 | #define GPRPCDEBUG(name, x) do { \ 65 | if (GP_RPC_DEBUG_LVL <= gp_debug) { \ 66 | if (x == NULL) { \ 67 | gp_debug_printf(" "); \ 68 | } else { \ 69 | gpdbg_##name(x); \ 70 | } \ 71 | } \ 72 | } while(0) 73 | 74 | #endif /* _GP_RPC_DEBUG_H_ */ 75 | -------------------------------------------------------------------------------- /src/client/gpm_wrap.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011,2012 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gssapi_gpm.h" 4 | #include "src/gp_conv.h" 5 | 6 | OM_uint32 gpm_wrap(OM_uint32 *minor_status, 7 | gssx_ctx *context_handle, 8 | int conf_req_flag, 9 | gss_qop_t qop_req, 10 | const gss_buffer_t input_message_buffer, 11 | int *conf_state, 12 | gss_buffer_t output_message_buffer) 13 | { 14 | union gp_rpc_arg uarg; 15 | union gp_rpc_res ures; 16 | gssx_arg_wrap *arg = &uarg.wrap; 17 | gssx_res_wrap *res = &ures.wrap; 18 | uint32_t ret_min = 0; 19 | uint32_t ret_maj = 0; 20 | int ret = 0; 21 | gssx_buffer message_buffer; 22 | 23 | memset(&uarg, 0, sizeof(union gp_rpc_arg)); 24 | memset(&ures, 0, sizeof(union gp_rpc_res)); 25 | 26 | if (!context_handle) { 27 | return GSS_S_CALL_INACCESSIBLE_READ; 28 | } 29 | 30 | /* format request */ 31 | /* NOTE: the final free will also release the old context */ 32 | arg->context_handle = *context_handle; 33 | arg->conf_req = conf_req_flag; 34 | arg->qop_state = qop_req; 35 | 36 | ret = gp_conv_buffer_to_gssx(input_message_buffer, &message_buffer); 37 | if (ret) { 38 | ret_maj = GSS_S_FAILURE; 39 | ret_min = ret; 40 | goto done; 41 | } 42 | arg->message_buffer.message_buffer_val = calloc(1, sizeof(gssx_buffer)); 43 | if (!arg->message_buffer.message_buffer_val) { 44 | ret_maj = GSS_S_FAILURE; 45 | ret_min = ENOMEM; 46 | goto done; 47 | } 48 | 49 | arg->message_buffer.message_buffer_val[0] = message_buffer; 50 | arg->message_buffer.message_buffer_len = 1; 51 | 52 | /* execute proxy request */ 53 | ret = gpm_make_call(GSSX_WRAP, &uarg, &ures); 54 | if (ret) { 55 | ret_maj = GSS_S_FAILURE; 56 | ret_min = ret; 57 | goto done; 58 | } 59 | 60 | /* format reply */ 61 | if (res->status.major_status) { 62 | gpm_save_status(&res->status); 63 | ret_min = res->status.minor_status; 64 | ret_maj = res->status.major_status; 65 | goto done; 66 | } 67 | 68 | if (conf_state) { 69 | *conf_state = *res->conf_state; 70 | } 71 | 72 | if (res->token_buffer.token_buffer_len > 0) { 73 | ret = gp_copy_gssx_to_buffer(&res->token_buffer.token_buffer_val[0], 74 | output_message_buffer); 75 | if (ret) { 76 | ret_maj = GSS_S_FAILURE; 77 | ret_min = ret; 78 | goto done; 79 | } 80 | } 81 | 82 | done: 83 | /* Steal the new context if available. 84 | * NOTE: We do not want it to be freed by xdr_free, so copy the contents 85 | * and cear up the structure to be freed so contents are not freed. */ 86 | if (res->context_handle) { 87 | *context_handle = *res->context_handle; 88 | memset(res->context_handle, 0, sizeof(gssx_ctx)); 89 | } else { 90 | /* prevent the contexthandle from being destroyed in case of server 91 | * error. */ 92 | memset(&arg->context_handle, 0, sizeof(gssx_ctx)); 93 | } 94 | 95 | gpm_free_xdrs(GSSX_WRAP, &uarg, &ures); 96 | *minor_status = ret_min; 97 | return ret_maj; 98 | } 99 | 100 | -------------------------------------------------------------------------------- /src/client/gpm_unwrap.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011,2012 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gssapi_gpm.h" 4 | #include "src/gp_conv.h" 5 | 6 | OM_uint32 gpm_unwrap(OM_uint32 *minor_status, 7 | gssx_ctx *context_handle, 8 | const gss_buffer_t input_message_buffer, 9 | gss_buffer_t output_message_buffer, 10 | int *conf_state, 11 | gss_qop_t *qop_state) 12 | { 13 | union gp_rpc_arg uarg; 14 | union gp_rpc_res ures; 15 | gssx_arg_unwrap *arg = &uarg.unwrap; 16 | gssx_res_unwrap *res = &ures.unwrap; 17 | uint32_t ret_min = 0; 18 | uint32_t ret_maj = 0; 19 | int ret = 0; 20 | gssx_buffer message_buffer; 21 | 22 | memset(&uarg, 0, sizeof(union gp_rpc_arg)); 23 | memset(&ures, 0, sizeof(union gp_rpc_res)); 24 | 25 | if (!context_handle) { 26 | return GSS_S_CALL_INACCESSIBLE_READ; 27 | } 28 | 29 | /* format request */ 30 | /* NOTE: the final free will also release the old context */ 31 | arg->context_handle = *context_handle; 32 | if (qop_state) { 33 | arg->qop_state = *qop_state; 34 | } 35 | 36 | ret = gp_conv_buffer_to_gssx(input_message_buffer, &message_buffer); 37 | if (ret) { 38 | ret_maj = GSS_S_FAILURE; 39 | ret_min = ret; 40 | goto done; 41 | } 42 | arg->token_buffer.token_buffer_val = calloc(1, sizeof(gssx_buffer)); 43 | if (!arg->token_buffer.token_buffer_val) { 44 | ret_maj = GSS_S_FAILURE; 45 | ret_min = ENOMEM; 46 | goto done; 47 | } 48 | 49 | arg->token_buffer.token_buffer_val[0] = message_buffer; 50 | arg->token_buffer.token_buffer_len = 1; 51 | 52 | /* execute proxy request */ 53 | ret = gpm_make_call(GSSX_UNWRAP, &uarg, &ures); 54 | if (ret) { 55 | ret_maj = GSS_S_FAILURE; 56 | ret_min = ret; 57 | goto done; 58 | } 59 | 60 | /* format reply */ 61 | if (res->status.major_status) { 62 | gpm_save_status(&res->status); 63 | ret_min = res->status.minor_status; 64 | ret_maj = res->status.major_status; 65 | goto done; 66 | } 67 | 68 | if (conf_state) { 69 | *conf_state = *res->conf_state; 70 | } 71 | if (qop_state) { 72 | *qop_state = *res->qop_state; 73 | } 74 | 75 | if (res->message_buffer.message_buffer_len > 0) { 76 | ret = gp_copy_gssx_to_buffer(&res->message_buffer.message_buffer_val[0], 77 | output_message_buffer); 78 | if (ret) { 79 | ret_maj = GSS_S_FAILURE; 80 | ret_min = ret; 81 | goto done; 82 | } 83 | } 84 | 85 | done: 86 | /* Steal the new context if available. 87 | * NOTE: We do not want it to be freed by xdr_free, so copy the contents 88 | * and cear up the structure to be freed so contents are not freed. */ 89 | if (res->context_handle) { 90 | *context_handle = *res->context_handle; 91 | memset(res->context_handle, 0, sizeof(gssx_ctx)); 92 | } else { 93 | /* prevent the contexthandle from being destroyed in case of server 94 | * error. */ 95 | memset(&arg->context_handle, 0, sizeof(gssx_ctx)); 96 | } 97 | 98 | gpm_free_xdrs(GSSX_UNWRAP, &uarg, &ures); 99 | *minor_status = ret_min; 100 | return ret_maj; 101 | } 102 | 103 | -------------------------------------------------------------------------------- /docs/Apache.md: -------------------------------------------------------------------------------- 1 | # Using GSS-Proxy for Apache httpd operation 2 | 3 | The traditional approach for performing Kerberos authentication in Apache 2.* is to use the mod_auth_gssapi (historically, mod_auth_kerb would have been used) module. When using this module, the Apache process must have read access to a keytab (configured with the ```GssapiCredStore``` option, or the default ```/etc/krb5.keytab```) containing keys for the HTTP service. This is not optimal from a security point of view as all websites can potentially get access to the key material. GSS-Proxy allows to implement privilege separation for the Apache httpd server by removing access to the keytab while preserving Kerberos authentication functionality. 4 | 5 | This page describes a setup which works starting with Fedora 21 with 6 | gssproxy-0.4.1-1.fc21.x86_64, httpd-2.4.16-1.fc21.x86_64, and 7 | mod_auth_gssapi-1.3.0-2.fc21.x86_64. It works on similar versions of RHEL as 8 | well. 9 | 10 | ## Setting up GSS-Proxy 11 | 12 | The proxy will need access to the HTTP/server-name@realm's keytab. When using IPA server, command 13 | 14 | ``` 15 | # ipa service-add HTTP/server-name 16 | ``` 17 | 18 | will create the service principal. On an IPA-enrolled client machine, the 19 | 20 | ``` 21 | # ipa-getkeytab -s $(awk '/^server =/ {print $3}' /etc/ipa/default.conf) -k /etc/gssproxy/http.keytab -p HTTP/$(hostname -f) 22 | ``` 23 | 24 | will retrieve the keytab for the principal. In the following configuration snippet we assume it is stored in ```/etc/gssproxy/http.keytab```. The permissions are set to 400, owner root. The Apache user does not have access to the keytab. 25 | 26 | We need to know the Apache user numerical id to put it in the configuration 27 | file, because GSS-Proxy uses the effective uid to distinguish the services. On 28 | my installation, the uid is 48. Symbolic uids are also supported (e.g., 29 | "httpd" or "apache"). 30 | 31 | We add a new section to the gssproxy configuration. To do this, copy the 32 | ```examples/80-httpd.conf``` file to ```/etc/gssproxy/80-httpd.conf```. (If 33 | you are using a monolithic config file at ```/etc/gssproxy/gssproxy.conf```, 34 | make sure the HTTP stanza preceeds any ```allow_any_uid=yes``` sections.) 35 | 36 | We then start the service: 37 | 38 | ``` 39 | # systemctl restart gssproxy.service 40 | # systemctl enable gssproxy.service 41 | ``` 42 | 43 | ## Setting up Apache 44 | 45 | For Apache, we need to know the location or directory that we want to protect. For testing purposes, we can create a simple file 46 | 47 | ``` 48 | # echo OK > /var/www/html/private 49 | ``` 50 | 51 | and configure mod_auth_gssapi to protect that location: 52 | 53 | ``` 54 | 55 | AuthType GSSAPI 56 | AuthName "GSSAPI Login" 57 | Require valid-user 58 | 59 | ``` 60 | 61 | in some ```/etc/httpd/conf.d/*.conf``` file. Note that the path to the keytab is not configured here since it will not be needed -- communication with GSS-Proxy via ```/var/lib/gssproxy/default.sock``` will be used instead. 62 | 63 | Furthermore, we need to tell the libraries to use the GSS-Proxy - create ```/etc/systemd/system/httpd.service``` with content 64 | 65 | ``` 66 | .include /lib/systemd/system/httpd.service 67 | [Service] 68 | Environment=GSS_USE_PROXY=1 69 | ``` 70 | 71 | Reload the configuration: 72 | 73 | ``` 74 | systemctl daemon-reload 75 | ``` 76 | 77 | When we now (re)start the Apache service 78 | 79 | ``` 80 | # systemctl restart httpd.service 81 | # systemctl enable httpd.service 82 | ``` 83 | 84 | we should be able to make HTTP requests against the server and they will be authenticated if the client has a valid Kerberos ticket. 85 | -------------------------------------------------------------------------------- /src/client/gpm_release_handle.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gssapi_gpm.h" 4 | 5 | OM_uint32 gpm_release_cred(OM_uint32 *minor_status, 6 | gssx_cred **cred_handle) 7 | { 8 | union gp_rpc_arg uarg; 9 | union gp_rpc_res ures; 10 | gssx_arg_release_handle *arg = &uarg.release_handle; 11 | gssx_res_release_handle *res = &ures.release_handle; 12 | gssx_cred *r; 13 | int ret; 14 | 15 | if (cred_handle == NULL || *cred_handle == NULL) { 16 | return 0; 17 | } 18 | 19 | r = (*cred_handle); 20 | 21 | if (!r->needs_release) { 22 | ret = GSS_S_COMPLETE; 23 | goto done; 24 | } 25 | 26 | memset(&uarg, 0, sizeof(union gp_rpc_arg)); 27 | memset(&ures, 0, sizeof(union gp_rpc_res)); 28 | 29 | /* ignore call_ctx for now */ 30 | 31 | arg->cred_handle.handle_type = GSSX_C_HANDLE_CRED; 32 | arg->cred_handle.gssx_handle_u.cred_info = *r; 33 | 34 | /* execute proxy request */ 35 | ret = gpm_make_call(GSSX_RELEASE_HANDLE, &uarg, &ures); 36 | if (ret) { 37 | *minor_status = ret; 38 | ret = GSS_S_FAILURE; 39 | goto rel_done; 40 | } 41 | 42 | if (res->status.major_status) { 43 | gpm_save_status(&res->status); 44 | *minor_status = res->status.minor_status; 45 | ret = res->status.major_status; 46 | } 47 | 48 | rel_done: 49 | /* we passed in our copy by value, so clean out to avoid double frees */ 50 | memset(&arg->cred_handle.gssx_handle_u.cred_info, 0, sizeof(gssx_cred)); 51 | gpm_free_xdrs(GSSX_RELEASE_HANDLE, &uarg, &ures); 52 | done: 53 | xdr_free((xdrproc_t)xdr_gssx_cred, (char *)r); 54 | free(r); 55 | *cred_handle = NULL; 56 | return ret; 57 | } 58 | 59 | OM_uint32 gpm_delete_sec_context(OM_uint32 *minor_status, 60 | gssx_ctx **context_handle, 61 | gss_buffer_t output_token UNUSED) 62 | { 63 | union gp_rpc_arg uarg; 64 | union gp_rpc_res ures; 65 | gssx_arg_release_handle *arg = &uarg.release_handle; 66 | gssx_res_release_handle *res = &ures.release_handle; 67 | gssx_ctx *r; 68 | int ret; 69 | 70 | if (context_handle == NULL || *context_handle == NULL) { 71 | return 0; 72 | } 73 | 74 | r = (*context_handle); 75 | 76 | if (!r->needs_release) { 77 | ret = GSS_S_COMPLETE; 78 | goto done; 79 | } 80 | 81 | memset(&uarg, 0, sizeof(union gp_rpc_arg)); 82 | memset(&ures, 0, sizeof(union gp_rpc_res)); 83 | 84 | /* ignore call_ctx for now */ 85 | 86 | arg->cred_handle.handle_type = GSSX_C_HANDLE_SEC_CTX; 87 | arg->cred_handle.gssx_handle_u.sec_ctx_info = *r; 88 | 89 | /* execute proxy request */ 90 | ret = gpm_make_call(GSSX_RELEASE_HANDLE, &uarg, &ures); 91 | if (ret) { 92 | *minor_status = ret; 93 | ret = GSS_S_FAILURE; 94 | goto rel_done; 95 | } 96 | 97 | if (res->status.major_status) { 98 | gpm_save_status(&res->status); 99 | *minor_status = res->status.minor_status; 100 | ret = res->status.major_status; 101 | } 102 | 103 | rel_done: 104 | /* we passed in our copy by value, so clean out to avoid double frees */ 105 | memset(&arg->cred_handle.gssx_handle_u.sec_ctx_info, 0, sizeof(gssx_cred)); 106 | gpm_free_xdrs(GSSX_RELEASE_HANDLE, &uarg, &ures); 107 | done: 108 | xdr_free((xdrproc_t)xdr_gssx_ctx, (char *)r); 109 | free(r); 110 | *context_handle = NULL; 111 | return ret; 112 | } 113 | -------------------------------------------------------------------------------- /src/gp_rpc_wrap.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011,2012 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gp_rpc_process.h" 4 | #include 5 | 6 | int gp_wrap(struct gp_call_ctx *gpcall UNUSED, 7 | union gp_rpc_arg *arg, 8 | union gp_rpc_res *res) 9 | { 10 | gss_buffer_desc input_message_buffer = GSS_C_EMPTY_BUFFER; 11 | gss_buffer_desc output_message_buffer = GSS_C_EMPTY_BUFFER; 12 | gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; 13 | struct gssx_arg_wrap *wa; 14 | struct gssx_res_wrap *wr; 15 | uint32_t ret_maj; 16 | uint32_t ret_min; 17 | int ret; 18 | int exp_ctx_type; 19 | int conf_state = 0; 20 | 21 | wa = &arg->wrap; 22 | wr = &res->wrap; 23 | 24 | GPRPCDEBUG(gssx_arg_wrap, wa); 25 | 26 | exp_ctx_type = gp_get_exported_context_type(&wa->call_ctx); 27 | if (exp_ctx_type == -1) { 28 | ret_maj = GSS_S_FAILURE; 29 | ret_min = EINVAL; 30 | goto done; 31 | } 32 | 33 | ret_maj = gp_import_gssx_to_ctx_id(&ret_min, 0, 34 | &wa->context_handle, 35 | &context_handle); 36 | if (ret_maj) { 37 | goto done; 38 | } 39 | 40 | /* apparently it is ok to send an empty message, in that case we dont need 41 | * to bother to do any conversion - gd */ 42 | if ((wa->message_buffer.message_buffer_len > 0) && 43 | (wa->message_buffer.message_buffer_val != NULL)) { 44 | gp_conv_gssx_to_buffer(&wa->message_buffer.message_buffer_val[0], 45 | &input_message_buffer); 46 | } 47 | 48 | ret_maj = gss_wrap(&ret_min, 49 | context_handle, 50 | wa->conf_req, 51 | wa->qop_state, 52 | &input_message_buffer, 53 | &conf_state, 54 | &output_message_buffer); 55 | if (ret_maj) { 56 | goto done; 57 | } 58 | 59 | wr->context_handle = calloc(1, sizeof(gssx_ctx)); 60 | if (!wr->context_handle) { 61 | ret_maj = GSS_S_FAILURE; 62 | ret_min = ENOMEM; 63 | goto done; 64 | } 65 | 66 | ret_maj = gp_export_ctx_id_to_gssx(&ret_min, exp_ctx_type, GSS_C_NO_OID, 67 | &context_handle, wr->context_handle); 68 | if (ret_maj) { 69 | goto done; 70 | } 71 | 72 | wr->qop_state = malloc(sizeof(gssx_qop)); 73 | if (!wr->qop_state) { 74 | ret_maj = GSS_S_FAILURE; 75 | ret_min = ENOMEM; 76 | goto done; 77 | } 78 | *wr->qop_state = wa->qop_state; 79 | 80 | wr->conf_state = malloc(sizeof(bool_t)); 81 | if (!wr->conf_state) { 82 | ret_maj = GSS_S_FAILURE; 83 | ret_min = ENOMEM; 84 | goto done; 85 | } 86 | *wr->conf_state = conf_state; 87 | 88 | wr->token_buffer.token_buffer_val = calloc(1, sizeof(gssx_buffer)); 89 | if (!wr->token_buffer.token_buffer_val) { 90 | ret_maj = GSS_S_FAILURE; 91 | ret_min = ENOMEM; 92 | goto done; 93 | } 94 | wr->token_buffer.token_buffer_len = 1; 95 | 96 | ret = gp_conv_buffer_to_gssx(&output_message_buffer, 97 | &wr->token_buffer.token_buffer_val[0]); 98 | if (ret ) { 99 | ret_maj = GSS_S_FAILURE; 100 | ret_min = ret; 101 | goto done; 102 | } 103 | 104 | ret_maj = GSS_S_COMPLETE; 105 | ret_min = 0; 106 | 107 | done: 108 | ret = gp_conv_status_to_gssx(ret_maj, ret_min, 109 | GSS_C_NO_OID, &wr->status); 110 | GPRPCDEBUG(gssx_res_wrap, wr); 111 | gss_release_buffer(&ret_min, &output_message_buffer); 112 | return ret; 113 | } 114 | -------------------------------------------------------------------------------- /src/gp_rpc_import_and_canon_name.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gp_rpc_process.h" 4 | 5 | 6 | /* NOTE: Very Important, before ever touching this function please read 7 | * carefully RFC 2744 section 3.10 "Names". 8 | * I am not kidding, if you hav not read it, go back and do it now, or do not 9 | * touch this function */ 10 | 11 | int gp_import_and_canon_name(struct gp_call_ctx *gpcall UNUSED, 12 | union gp_rpc_arg *arg, 13 | union gp_rpc_res *res) 14 | { 15 | struct gssx_arg_import_and_canon_name *icna; 16 | struct gssx_res_import_and_canon_name *icnr; 17 | gss_OID mech = GSS_C_NO_OID; 18 | gss_name_t import_name = GSS_C_NO_NAME; 19 | gss_name_t output_name = GSS_C_NO_NAME; 20 | gss_buffer_desc localname = GSS_C_EMPTY_BUFFER; 21 | struct gssx_option *val = NULL; 22 | uint32_t ret_maj = 0; 23 | uint32_t ret_min = 0; 24 | int ret; 25 | 26 | icna = &arg->import_and_canon_name; 27 | icnr = &res->import_and_canon_name; 28 | 29 | GPRPCDEBUG(gssx_arg_import_and_canon_name, icna); 30 | 31 | if (icna->input_name.display_name.octet_string_len == 0 && 32 | icna->input_name.exported_name.octet_string_len == 0) { 33 | ret_maj = GSS_S_FAILURE; 34 | ret_min = EINVAL; 35 | goto done; 36 | } 37 | 38 | ret_maj = gp_conv_gssx_to_name(&ret_min, &icna->input_name, &import_name); 39 | if (ret_maj) { 40 | goto done; 41 | } 42 | 43 | if (icna->mech.octet_string_len != 0) { 44 | 45 | ret = gp_conv_gssx_to_oid_alloc(&icna->mech, &mech); 46 | if (ret) { 47 | ret_maj = GSS_S_FAILURE; 48 | ret_min = ret; 49 | goto done; 50 | } 51 | } 52 | 53 | /* We implement gss_localname in this function via a special option */ 54 | gp_options_find(val, icna->options, 55 | LOCALNAME_OPTION, sizeof(LOCALNAME_OPTION)); 56 | if (val) { 57 | ret_maj = gss_localname(&ret_min, import_name, mech, &localname); 58 | if (ret_maj) { 59 | goto done; 60 | } 61 | ret_min = gp_add_option(&icnr->options.options_val, 62 | &icnr->options.options_len, 63 | LOCALNAME_OPTION, 64 | sizeof(LOCALNAME_OPTION), 65 | localname.value, 66 | localname.length); 67 | if (ret_min) { 68 | ret_maj = GSS_S_FAILURE; 69 | } 70 | 71 | goto done; 72 | } 73 | 74 | /* regular import/canon part */ 75 | if (mech != GSS_C_NO_OID) { 76 | 77 | ret_maj = gss_canonicalize_name(&ret_min, import_name, 78 | mech, &output_name); 79 | if (ret_maj) { 80 | goto done; 81 | } 82 | 83 | ret_maj = gp_conv_name_to_gssx_alloc(&ret_min, 84 | output_name, &icnr->output_name); 85 | } else { 86 | ret_maj = gp_conv_name_to_gssx_alloc(&ret_min, 87 | import_name, &icnr->output_name); 88 | } 89 | 90 | /* TODO: check also icna->input_name.exported_composite_name */ 91 | /* TODO: icna->name_attributes */ 92 | 93 | done: 94 | ret = gp_conv_status_to_gssx(ret_maj, ret_min, mech, 95 | &icnr->status); 96 | GPRPCDEBUG(gssx_res_import_and_canon_name, icnr); 97 | 98 | gss_release_oid(&ret_min, &mech); 99 | gss_release_name(&ret_min, &import_name); 100 | gss_release_name(&ret_min, &output_name); 101 | gss_release_buffer(&ret_min, &localname); 102 | return ret; 103 | } 104 | -------------------------------------------------------------------------------- /contrib/gssproxy.spec.in: -------------------------------------------------------------------------------- 1 | Name: @PACKAGE_NAME@ 2 | Version: @PACKAGE_VERSION@ 3 | Release: 0@PRERELEASE_VERSION@%{?dist} 4 | Summary: GSSAPI Proxy 5 | 6 | Group: System Environment/Libraries 7 | License: MIT 8 | URL: https://github.com/gssapi/gssproxy 9 | Source0: https://github.com/gssapi/gssproxy/releases/download/v%{version}/%{name}-%{version}.tar.gz 10 | BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) 11 | 12 | %global servicename gssproxy 13 | %global pubconfpath %{_sysconfdir}/gssproxy 14 | %global gpstatedir %{_localstatedir}/lib/gssproxy 15 | 16 | ### Patches ### 17 | 18 | ### Dependencies ### 19 | Requires: krb5-libs >= 1.12.0 20 | Requires: keyutils-libs 21 | Requires: libverto-module-base 22 | Requires: libini_config 23 | Requires(post): systemd-units 24 | Requires(preun): systemd-units 25 | Requires(postun): systemd-units 26 | 27 | ### Build Dependencies ### 28 | BuildRequires: autoconf 29 | BuildRequires: automake 30 | BuildRequires: libtool 31 | BuildRequires: m4 32 | BuildRequires: libxslt 33 | BuildRequires: libxml2 34 | BuildRequires: docbook-style-xsl 35 | BuildRequires: doxygen 36 | BuildRequires: gettext-devel 37 | BuildRequires: pkgconfig 38 | BuildRequires: krb5-devel >= 1.12.0 39 | BuildRequires: libselinux-devel 40 | BuildRequires: keyutils-libs-devel 41 | BuildRequires: libini_config-devel >= 1.2.0 42 | BuildRequires: libverto-devel 43 | BuildRequires: libcap-devel 44 | BuildRequires: popt-devel 45 | BuildRequires: findutils 46 | BuildRequires: systemd-units 47 | BuildRequires: systemd-devel 48 | 49 | 50 | %description 51 | A proxy for GSSAPI credential handling 52 | 53 | %prep 54 | %setup -q 55 | 56 | # patch 57 | 58 | %build 59 | autoreconf -f -i 60 | %configure \ 61 | --with-pubconf-path=%{pubconfpath} \ 62 | --with-initscript=systemd \ 63 | --disable-static \ 64 | --disable-rpath \ 65 | --with-gpp-default-behavior=REMOTE_FIRST 66 | 67 | make %{?_smp_mflags} all 68 | make test_proxymech 69 | 70 | %install 71 | rm -rf %{buildroot} 72 | make install DESTDIR=%{buildroot} 73 | rm -f %{buildroot}%{_libdir}/gssproxy/proxymech.la 74 | install -d -m755 %{buildroot}%{_sysconfdir}/gssproxy 75 | install -m644 examples/gssproxy.conf %{buildroot}%{_sysconfdir}/gssproxy/gssproxy.conf 76 | install -m644 examples/24-nfs-server.conf %{buildroot}%{_sysconfdir}/gssproxy/24-nfs-server.conf 77 | install -m644 examples/99-network-fs-clients.conf %{buildroot}%{_sysconfdir}/gssproxy/99-network-fs-clients.conf 78 | install -d -m755 %{buildroot}%{_sysconfdir}/gss/mech.d 79 | install -m644 examples/proxymech.conf %{buildroot}%{_sysconfdir}/gss/mech.d/proxymech.conf 80 | mkdir -p %{buildroot}%{gpstatedir}/rcache 81 | 82 | %clean 83 | rm -rf %{buildroot} 84 | 85 | 86 | %files 87 | %defattr(-,root,root,-) 88 | %doc COPYING 89 | %{_unitdir}/gssproxy.service 90 | %{_userunitdir}/gssuserproxy.service 91 | %{_userunitdir}/gssuserproxy.socket 92 | %{_sbindir}/gssproxy 93 | %attr(755,root,root) %dir %{pubconfpath} 94 | %attr(755,root,root) %dir %{gpstatedir} 95 | %attr(700,root,root) %dir %{gpstatedir}/clients 96 | %attr(700,root,root) %dir %{gpstatedir}/rcache 97 | %attr(0600,root,root) %config(noreplace) /%{_sysconfdir}/gssproxy/gssproxy.conf 98 | %attr(0600,root,root) %config(noreplace) /%{_sysconfdir}/gssproxy/24-nfs-server.conf 99 | %attr(0600,root,root) %config(noreplace) /%{_sysconfdir}/gssproxy/99-network-fs-clients.conf 100 | %attr(0644,root,root) %config(noreplace) /%{_sysconfdir}/gss/mech.d/proxymech.conf 101 | %{_libdir}/gssproxy/proxymech.so 102 | %{_mandir}/man5/gssproxy.conf.5* 103 | %{_mandir}/man8/gssproxy.8* 104 | %{_mandir}/man8/gssproxy-mech.8* 105 | 106 | %post 107 | %systemd_post gssproxy.service 108 | 109 | %preun 110 | %systemd_preun gssproxy.service 111 | 112 | %postun 113 | %systemd_postun_with_restart gssproxy.service 114 | 115 | %changelog 116 | %autochangelog 117 | -------------------------------------------------------------------------------- /src/gp_rpc_unwrap.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011,2012 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gp_rpc_process.h" 4 | #include 5 | 6 | int gp_unwrap(struct gp_call_ctx *gpcall UNUSED, 7 | union gp_rpc_arg *arg, 8 | union gp_rpc_res *res) 9 | { 10 | gss_buffer_desc input_message_buffer = GSS_C_EMPTY_BUFFER; 11 | gss_buffer_desc output_message_buffer = GSS_C_EMPTY_BUFFER; 12 | gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; 13 | struct gssx_arg_unwrap *uwa; 14 | struct gssx_res_unwrap *uwr; 15 | uint32_t ret_maj; 16 | uint32_t ret_min; 17 | int ret; 18 | int exp_ctx_type; 19 | int conf_state = 0; 20 | gss_qop_t qop_state = 0; 21 | 22 | uwa = &arg->unwrap; 23 | uwr = &res->unwrap; 24 | 25 | GPRPCDEBUG(gssx_arg_unwrap, uwa); 26 | 27 | exp_ctx_type = gp_get_exported_context_type(&uwa->call_ctx); 28 | if (exp_ctx_type == -1) { 29 | ret_maj = GSS_S_FAILURE; 30 | ret_min = EINVAL; 31 | goto done; 32 | } 33 | 34 | ret_maj = gp_import_gssx_to_ctx_id(&ret_min, 0, 35 | &uwa->context_handle, 36 | &context_handle); 37 | if (ret_maj) { 38 | goto done; 39 | } 40 | 41 | /* apparently it is ok to send an empty message, in that case we dont need 42 | * to bother to do any conversion - gd */ 43 | if ((uwa->token_buffer.token_buffer_len > 0) && 44 | (uwa->token_buffer.token_buffer_val != NULL)) { 45 | gp_conv_gssx_to_buffer(&uwa->token_buffer.token_buffer_val[0], 46 | &input_message_buffer); 47 | } 48 | 49 | ret_maj = gss_unwrap(&ret_min, 50 | context_handle, 51 | &input_message_buffer, 52 | &output_message_buffer, 53 | &conf_state, 54 | &qop_state); 55 | if (ret_maj) { 56 | goto done; 57 | } 58 | 59 | uwr->context_handle = calloc(1, sizeof(gssx_ctx)); 60 | if (!uwr->context_handle) { 61 | ret_maj = GSS_S_FAILURE; 62 | ret_min = ENOMEM; 63 | goto done; 64 | } 65 | 66 | ret_maj = gp_export_ctx_id_to_gssx(&ret_min, exp_ctx_type, GSS_C_NO_OID, 67 | &context_handle, 68 | uwr->context_handle); 69 | if (ret_maj) { 70 | goto done; 71 | } 72 | 73 | uwr->qop_state = malloc(sizeof(gssx_qop)); 74 | if (!uwr->qop_state) { 75 | ret_maj = GSS_S_FAILURE; 76 | ret_min = ENOMEM; 77 | goto done; 78 | } 79 | *uwr->qop_state = uwa->qop_state; 80 | 81 | uwr->conf_state = malloc(sizeof(bool_t)); 82 | if (!uwr->conf_state) { 83 | ret_maj = GSS_S_FAILURE; 84 | ret_min = ENOMEM; 85 | goto done; 86 | } 87 | *uwr->conf_state = conf_state; 88 | 89 | uwr->message_buffer.message_buffer_val = calloc(1, sizeof(gssx_buffer)); 90 | if (!uwr->message_buffer.message_buffer_val) { 91 | ret_maj = GSS_S_FAILURE; 92 | ret_min = ENOMEM; 93 | goto done; 94 | } 95 | uwr->message_buffer.message_buffer_len = 1; 96 | 97 | ret = gp_conv_buffer_to_gssx(&output_message_buffer, 98 | &uwr->message_buffer.message_buffer_val[0]); 99 | if (ret ) { 100 | ret_maj = GSS_S_FAILURE; 101 | ret_min = ret; 102 | goto done; 103 | } 104 | 105 | ret_maj = GSS_S_COMPLETE; 106 | ret_min = 0; 107 | 108 | done: 109 | ret = gp_conv_status_to_gssx(ret_maj, ret_min, 110 | GSS_C_NO_OID, 111 | &uwr->status); 112 | GPRPCDEBUG(gssx_res_unwrap, uwr); 113 | gss_release_buffer(&ret_min, &output_message_buffer); 114 | return ret; 115 | } 116 | -------------------------------------------------------------------------------- /src/extract_ccache.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2020 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "config.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "gp_proxy.h" 10 | #include 11 | 12 | int extract_ccache(char *ccache_name, char *dest_ccache) 13 | { 14 | krb5_context ctx = NULL; 15 | krb5_ccache ccache = NULL; 16 | krb5_creds cred = { 0 }; 17 | krb5_creds icred = { 0 }; 18 | krb5_enc_data enc_handle = { 0 }; 19 | krb5_data data_out = { 0 }; 20 | krb5_error_code ret; 21 | gssx_cred xcred = { 0 }; 22 | XDR xdrctx; 23 | bool xdrok; 24 | struct gp_creds_handle *handle = NULL; 25 | gss_buffer_desc token = GSS_C_EMPTY_BUFFER; 26 | gss_cred_id_t gcred = NULL; 27 | gss_key_value_element_desc element; 28 | gss_key_value_set_desc store; 29 | gss_key_value_set_desc *store_p = NULL; 30 | uint32_t ret_maj = GSS_S_COMPLETE; 31 | uint32_t ret_min = 0; 32 | uint8_t pad; 33 | size_t last_byte; 34 | size_t i; 35 | 36 | ret = krb5_init_context(&ctx); 37 | if (ret) goto done; 38 | 39 | ret = krb5_cc_resolve(ctx, ccache_name, &ccache); 40 | if (ret) goto done; 41 | 42 | ret = krb5_cc_get_principal(ctx, ccache, &icred.client); 43 | if (ret) goto done; 44 | 45 | ret = krb5_parse_name(ctx, GPKRB_SRV_NAME, &icred.server); 46 | if (ret) goto done; 47 | 48 | ret = krb5_cc_retrieve_cred(ctx, ccache, 0, &icred, &cred); 49 | if (ret) goto done; 50 | 51 | xdrmem_create(&xdrctx, cred.ticket.data, cred.ticket.length, XDR_DECODE); 52 | xdrok = xdr_gssx_cred(&xdrctx, &xcred); 53 | if (!xdrok) { 54 | ret = EIO; 55 | goto done; 56 | } 57 | 58 | ret_maj = gp_init_creds_handle(&ret_min, "Extract Ccache", NULL, &handle); 59 | if (ret_maj) { 60 | ret = ret_min; 61 | goto done; 62 | } 63 | 64 | enc_handle.enctype = handle->key->enctype; 65 | enc_handle.ciphertext.data = 66 | xcred.cred_handle_reference.octet_string_val; 67 | enc_handle.ciphertext.length = 68 | xcred.cred_handle_reference.octet_string_len; 69 | 70 | data_out.length = enc_handle.ciphertext.length; 71 | data_out.data = malloc(enc_handle.ciphertext.length); 72 | if (!data_out.data) { 73 | ret = ENOMEM; 74 | goto done; 75 | } 76 | 77 | ret = krb5_c_decrypt(handle->context, handle->key, 78 | KRB5_KEYUSAGE_APP_DATA_ENCRYPT, 79 | NULL, &enc_handle, &data_out); 80 | if (ret) goto done; 81 | fprintf(stderr, "decrypted\n"); 82 | 83 | /* Handle the padding. */ 84 | last_byte = data_out.length - 1; 85 | pad = data_out.data[last_byte]; 86 | if (pad >= ENC_MIN_PAD_LEN && pad < last_byte) { 87 | for (i = last_byte - pad; i <= last_byte; i++) { 88 | if (pad != data_out.data[i]) break; 89 | } 90 | if (i == last_byte) { 91 | /* they all match, this is padding, remove it */ 92 | data_out.length -= pad; 93 | } 94 | } 95 | 96 | token.value = data_out.data; 97 | token.length = data_out.length; 98 | ret_maj = gss_import_cred(&ret_min, &token, &gcred); 99 | if (ret_maj) { 100 | gp_log_failure(GSS_C_NULL_OID, ret_maj, ret_min); 101 | ret = ret_min; 102 | goto done; 103 | } 104 | 105 | /* store in destination ccache if any, or default ccache */ 106 | if (dest_ccache) { 107 | element.key = "ccache"; 108 | element.value = dest_ccache; 109 | store.elements = &element; 110 | store.count = 1; 111 | store_p = &store; 112 | } 113 | 114 | ret_maj = gss_store_cred_into(&ret_min, gcred, GSS_C_BOTH, 115 | GSS_C_NULL_OID, 1, 1, store_p, NULL, NULL); 116 | if (ret_maj) { 117 | gp_log_failure(GSS_C_NULL_OID, ret_maj, ret_min); 118 | ret = ret_min; 119 | goto done; 120 | } 121 | 122 | done: 123 | if (ctx) { 124 | krb5_free_cred_contents(ctx, &cred); 125 | krb5_free_cred_contents(ctx, &icred); 126 | if (ccache) krb5_cc_close(ctx, ccache); 127 | krb5_free_context(ctx); 128 | } 129 | xdr_free((xdrproc_t)xdr_gssx_cred, (char *)&xcred); 130 | gp_free_creds_handle(&handle); 131 | gss_release_cred(&ret_min, &gcred); 132 | free(data_out.data); 133 | return ret; 134 | } 135 | -------------------------------------------------------------------------------- /src/client/gpm_display_status.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gssapi_gpm.h" 4 | #include 5 | 6 | static pthread_key_t gpm_last_status; 7 | 8 | static void gpm_destroy_last_status(void *arg) 9 | { 10 | gssx_status *status = (gssx_status *)arg; 11 | xdr_free((xdrproc_t)xdr_gssx_status, (char *)status); 12 | free(status); 13 | } 14 | 15 | void gpm_display_status_init_once(void) 16 | { 17 | (void)pthread_key_create(&gpm_last_status, gpm_destroy_last_status); 18 | } 19 | 20 | /* Portable thread local storage for return status. */ 21 | void gpm_save_status(gssx_status *status) 22 | { 23 | gssx_status *last_status; 24 | int ret; 25 | 26 | last_status = (gssx_status *)pthread_getspecific(gpm_last_status); 27 | if (last_status != NULL) { 28 | /* store NULL first so we do not risk a double free if we are 29 | * racing on a pthread_cancel */ 30 | pthread_setspecific(gpm_last_status, NULL); 31 | gpm_destroy_last_status(last_status); 32 | } 33 | 34 | ret = gp_copy_gssx_status_alloc(status, &last_status); 35 | if (ret == 0) { 36 | pthread_setspecific(gpm_last_status, last_status); 37 | } 38 | } 39 | 40 | gssx_status *gpm_get_saved_status(void) 41 | { 42 | return (gssx_status *)pthread_getspecific(gpm_last_status); 43 | } 44 | 45 | /* This funciton is used to record internal mech errors that are 46 | * generated by the proxy client code */ 47 | void gpm_save_internal_status(uint32_t err, char *err_str) 48 | { 49 | gssx_status status; 50 | 51 | memset(&status, 0, sizeof(gssx_status)); 52 | 53 | #define STD_MAJ_ERROR_STR "Internal gssproxy error" 54 | status.major_status = GSS_S_FAILURE; 55 | status.major_status_string.utf8string_val = strdup(STD_MAJ_ERROR_STR); 56 | status.major_status_string.utf8string_len = sizeof(STD_MAJ_ERROR_STR); 57 | status.minor_status = err; 58 | status.minor_status_string.utf8string_val = err_str; 59 | status.minor_status_string.utf8string_len = strlen(err_str) + 1; 60 | gpm_save_status(&status); 61 | } 62 | 63 | OM_uint32 gpm_display_status(OM_uint32 *minor_status, 64 | OM_uint32 status_value, 65 | int status_type, 66 | const gss_OID mech_type UNUSED, 67 | OM_uint32 *message_context, 68 | gss_buffer_t status_string) 69 | { 70 | gssx_status *last_status = gpm_get_saved_status(); 71 | utf8string tmp; 72 | int ret; 73 | 74 | switch(status_type) { 75 | case GSS_C_GSS_CODE: 76 | if (last_status && 77 | last_status->major_status == status_value && 78 | last_status->major_status_string.utf8string_len) { 79 | ret = gp_copy_utf8string(&last_status->major_status_string, 80 | &tmp); 81 | if (ret) { 82 | *minor_status = ret; 83 | return GSS_S_FAILURE; 84 | } 85 | status_string->value = tmp.utf8string_val; 86 | status_string->length = tmp.utf8string_len; 87 | *minor_status = 0; 88 | return GSS_S_COMPLETE; 89 | } else { 90 | /* if we do not have it, make it clear */ 91 | return GSS_S_UNAVAILABLE; 92 | } 93 | case GSS_C_MECH_CODE: 94 | if (last_status && 95 | last_status->minor_status == status_value && 96 | last_status->minor_status_string.utf8string_len) { 97 | 98 | if (*message_context) { 99 | /* we do not support multiple messages for now */ 100 | *minor_status = EINVAL; 101 | return GSS_S_FAILURE; 102 | } 103 | 104 | ret = gp_copy_utf8string(&last_status->minor_status_string, 105 | &tmp); 106 | if (ret) { 107 | *minor_status = ret; 108 | return GSS_S_FAILURE; 109 | } 110 | status_string->value = tmp.utf8string_val; 111 | status_string->length = tmp.utf8string_len; 112 | } else { 113 | /* if we do not have it, make it clear */ 114 | return GSS_S_UNAVAILABLE; 115 | } 116 | *minor_status = 0; 117 | return GSS_S_COMPLETE; 118 | default: 119 | *minor_status = EINVAL; 120 | return GSS_S_BAD_STATUS; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /external/dinglibs.m4: -------------------------------------------------------------------------------- 1 | AC_DEFUN([WITH_LIBINI_CONFIG], 2 | [ 3 | PKG_CHECK_MODULES([LIBINI_CONFIG], [ini_config >= 1.2.0], 4 | [ 5 | INI_CONFIG_CFLAGS="`$PKG_CONFIG --cflags ini_config`" 6 | INI_CONFIG_LIBS="`$PKG_CONFIG --libs ini_config`" 7 | AC_CHECK_LIB(ini_config, ini_config_file_open, [], 8 | [AC_MSG_ERROR([ini_config library must support ini_config_file_open])], 9 | [$INI_CONFIG_LIBS]) 10 | AC_CHECK_LIB(ini_config, ini_config_augment, [], 11 | [AC_MSG_ERROR([ini_config library must support ini_config_augment])], 12 | [$INI_CONFIG_LIBS]) 13 | have_libini_config=yes 14 | ], [ 15 | AC_MSG_ERROR([Could not find LIBINI_CONFIG headers]) 16 | have_libini_config=no 17 | ]) 18 | ]) 19 | 20 | AC_DEFUN([WITH_REF_ARRAY], [ 21 | 22 | AC_CHECK_LIB(ref_array, ref_array_destroy, [], 23 | [AC_MSG_ERROR([library must support ref_array_destroy])], 24 | [$INI_CONFIG_LIBS]) 25 | 26 | AC_RUN_IFELSE([AC_LANG_SOURCE([[ 27 | /* See: https://pagure.io/SSSD/ding-libs/pull-request/3172 */ 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | static int write_to_file(char *path, char *text) 38 | { 39 | FILE *f = fopen(path, "w"); 40 | int bytes = 0; 41 | if (f == NULL) 42 | return 1; 43 | 44 | bytes = fprintf(f, "%s", text); 45 | if (bytes < 0 || (size_t)bytes != strlen(text)) 46 | return 1; 47 | 48 | return fclose(f); 49 | } 50 | 51 | int main(void) 52 | { 53 | char base_path[PATH_MAX]; 54 | char augment_path[PATH_MAX]; 55 | 56 | char config_base[] = 57 | "[section]\n" 58 | "key1 = first\n" 59 | "key2 = exists\n"; 60 | 61 | char config_augment[] = 62 | "[section]\n" 63 | "key1 = augment\n" 64 | "key3 = exists\n"; 65 | 66 | char *builddir; 67 | 68 | struct ini_cfgobj *in_cfg, *result_cfg; 69 | struct ini_cfgfile *file_ctx; 70 | 71 | uint32_t merge_flags = INI_MS_DETECT | INI_MS_PRESERVE; 72 | 73 | int ret; 74 | 75 | builddir = getenv("builddir"); 76 | if (builddir == NULL) { 77 | builddir = strdup("."); 78 | } 79 | 80 | snprintf(base_path, PATH_MAX, "%s/tmp_augment_base.conf", builddir); 81 | snprintf(augment_path, PATH_MAX, "%s/tmp_augment_augment.conf", builddir); 82 | 83 | ret = write_to_file(base_path, config_base); 84 | if (ret != 0) { 85 | ret = 1; 86 | goto cleanup; 87 | } 88 | 89 | ret = write_to_file(augment_path, config_augment); 90 | if (ret != 0) { 91 | goto cleanup; 92 | } 93 | 94 | /* Match only augment.conf */ 95 | const char *m_patterns[] = { "^tmp_augment_augment.conf$", NULL }; 96 | 97 | /* Match all sections */ 98 | const char *m_sections[] = { ".*", NULL }; 99 | 100 | /* Create config collection */ 101 | ret = ini_config_create(&in_cfg); 102 | if (ret != EOK) 103 | goto cleanup; 104 | 105 | /* Open base.conf */ 106 | ret = ini_config_file_open(base_path, 0, &file_ctx); 107 | if (ret != EOK) 108 | goto cleanup; 109 | 110 | /* Seed in_cfg with base.conf */ 111 | ret = ini_config_parse(file_ctx, 1, 0, 0, in_cfg); 112 | if (ret != EOK) 113 | goto cleanup; 114 | 115 | /* Update base.conf with augment.conf */ 116 | ret = ini_config_augment(in_cfg, 117 | builddir, 118 | m_patterns, 119 | m_sections, 120 | NULL, 121 | INI_STOP_ON_NONE, 122 | 0, 123 | INI_PARSE_NOSPACE|INI_PARSE_NOTAB, 124 | merge_flags, 125 | &result_cfg, 126 | NULL, 127 | NULL); 128 | /* We always expect EEXIST due to DETECT being set. */ 129 | if (ret != EEXIST) 130 | goto cleanup; 131 | 132 | ret = 0; 133 | 134 | cleanup: 135 | remove(base_path); 136 | remove(augment_path); 137 | 138 | /* Per autoconf guidelines */ 139 | if (ret != 0) 140 | ret = 1; 141 | 142 | return ret; 143 | } 144 | ]])] 145 | ,, [AC_MSG_ERROR(["ini_config library must support extended INI_MS_DETECT. See: https://pagure.io/SSSD/ding-libs/pull-request/3172"])]) 146 | 147 | ]) 148 | -------------------------------------------------------------------------------- /tests/t_init.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "t_utils.h" 4 | 5 | int main(int argc, const char *argv[]) 6 | { 7 | char buffer[MAX_RPC_SIZE]; 8 | uint32_t buflen; 9 | gss_cred_id_t cred_handle = GSS_C_NO_CREDENTIAL; 10 | gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; 11 | gss_buffer_desc in_token = GSS_C_EMPTY_BUFFER; 12 | gss_buffer_desc out_token = GSS_C_EMPTY_BUFFER; 13 | gss_name_t name; 14 | gss_name_t i_name; 15 | gss_OID_set_desc oid_set = { 1, discard_const(gss_mech_krb5) }; 16 | uint32_t ret_maj; 17 | uint32_t ret_min; 18 | int ret = -1; 19 | 20 | ret = t_string_to_name(argv[1], &name, GSS_C_NT_HOSTBASED_SERVICE); 21 | if (ret) { 22 | DEBUG("Failed to import server name from argv[1]\n"); 23 | ret = -1; 24 | goto done; 25 | } 26 | 27 | if (argc > 2) { 28 | ret = t_string_to_name(argv[2], &i_name, 29 | discard_const(GSS_KRB5_NT_PRINCIPAL_NAME)); 30 | if (ret) { 31 | DEBUG("Failed to import client name from argv[2]\n"); 32 | ret = -1; 33 | goto done; 34 | } 35 | 36 | ret_maj = gss_acquire_cred(&ret_min, 37 | i_name, 38 | GSS_C_INDEFINITE, 39 | &oid_set, 40 | GSS_C_INITIATE, 41 | &cred_handle, 42 | NULL, NULL); 43 | if (ret_maj != GSS_S_COMPLETE) { 44 | DEBUG("gss_acquire_cred() failed\n"); 45 | t_log_failure(GSS_C_NO_OID, ret_maj, ret_min); 46 | ret = -1; 47 | goto done; 48 | } 49 | } 50 | 51 | ret_maj = gss_init_sec_context(&ret_min, 52 | cred_handle, 53 | &context_handle, 54 | name, 55 | GSS_C_NO_OID, 56 | GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG, 57 | 0, 58 | GSS_C_NO_CHANNEL_BINDINGS, 59 | &in_token, 60 | NULL, 61 | &out_token, 62 | NULL, 63 | NULL); 64 | if (ret_maj != GSS_S_CONTINUE_NEEDED) { 65 | DEBUG("gss_init_sec_context() failed\n"); 66 | t_log_failure(GSS_C_NO_OID, ret_maj, ret_min); 67 | ret = -1; 68 | goto done; 69 | } 70 | 71 | /* We get stuff from stdin and spit it out on stderr */ 72 | if (!out_token.length) { 73 | DEBUG("No output token ?"); 74 | ret = -1; 75 | goto done; 76 | } 77 | 78 | ret = t_send_buffer(STDOUT_FD, out_token.value, out_token.length); 79 | if (ret) { 80 | DEBUG("Failed to send data to server!\n"); 81 | ret = -1; 82 | goto done; 83 | } 84 | 85 | gss_release_buffer(&ret_min, &out_token); 86 | 87 | ret = t_recv_buffer(STDIN_FD, buffer, &buflen); 88 | if (ret != 0) { 89 | DEBUG("Failed to read token from STDIN\n"); 90 | ret = -1; 91 | goto done; 92 | } 93 | 94 | in_token.value = buffer; 95 | in_token.length = buflen; 96 | 97 | ret_maj = gss_init_sec_context(&ret_min, 98 | cred_handle, 99 | &context_handle, 100 | name, 101 | GSS_C_NO_OID, 102 | GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG, 103 | 0, 104 | GSS_C_NO_CHANNEL_BINDINGS, 105 | &in_token, 106 | NULL, 107 | &out_token, 108 | NULL, 109 | NULL); 110 | if (ret_maj) { 111 | DEBUG("Error initializing context\n"); 112 | t_log_failure(GSS_C_NO_OID, ret_maj, ret_min); 113 | ret = -1; 114 | goto done; 115 | } 116 | 117 | ret = 0; 118 | 119 | done: 120 | gss_delete_sec_context(&ret_min, &context_handle, NULL); 121 | gss_release_cred(&ret_min, &cred_handle); 122 | gss_release_buffer(&ret_min, &out_token); 123 | gss_release_name(&ret_min, &name); 124 | return ret; 125 | } 126 | -------------------------------------------------------------------------------- /tests/userproxytest.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2022 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #define _GNU_SOURCE 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | char *srv_args[] = { 16 | "./gssproxy", 17 | "-u", "-i", 18 | "-d", "--debug-level=1", 19 | "-s", "./testdir/userproxytest.sock", 20 | "--idle-timeout=3", 21 | NULL 22 | }; 23 | 24 | int mock_activation_sockets(void) 25 | { 26 | struct sockaddr_un addr = { 27 | .sun_family = AF_UNIX, 28 | .sun_path = "./testdir/userproxytest.sock", 29 | }; 30 | int fd; 31 | int ret; 32 | 33 | unlink(addr.sun_path); 34 | 35 | fd = socket(AF_UNIX, SOCK_STREAM, 0); 36 | if (fd == -1) { 37 | ret = -1; 38 | goto done; 39 | } 40 | 41 | ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); 42 | if (ret == -1) goto done; 43 | 44 | ret = listen(fd, 1); 45 | if (ret == -1) goto done; 46 | 47 | done: 48 | if (ret == -1) close(fd); 49 | return 0; 50 | } 51 | 52 | int mock_activation_environment(void) 53 | { 54 | char *onestr = "1"; 55 | char *pidstr; 56 | int ret; 57 | 58 | ret = asprintf(&pidstr, "%u", (unsigned)getpid()); 59 | if (ret == -1) return -1; 60 | 61 | setenv("LISTEN_PID", pidstr, 1); 62 | setenv("LISTEN_FDS", onestr, 1); 63 | 64 | free(pidstr); 65 | return 0; 66 | } 67 | 68 | int wait_and_check_output(int outfd, int timeout) 69 | { 70 | struct { 71 | const char *match; 72 | bool matched; 73 | } checks[] = { 74 | { "Initialization complete.", false }, 75 | { "Terminating, after idling", false }, 76 | { NULL, true } 77 | }; 78 | time_t start = time(NULL); 79 | time_t now = start; 80 | useconds_t interval = 100 * 1000; /* 100 msec */ 81 | char outbuf[1024]; 82 | char *line; 83 | FILE *out = NULL; 84 | int err, ret = -1; 85 | 86 | /* make pipe non blocking */ 87 | err = fcntl(outfd, F_SETFL, O_NONBLOCK); 88 | if (err) goto done; 89 | 90 | out = fdopen(outfd, "r"); 91 | if (!out) goto done; 92 | 93 | while (now < start + timeout) { 94 | err = usleep(interval); 95 | if (err) goto done; 96 | 97 | line = fgets(outbuf, 1023, out); 98 | if (line) { 99 | for (int i = 0; checks[i].match != NULL; i++) { 100 | if (strstr(line, checks[i].match)) { 101 | checks[i].matched = true; 102 | } 103 | } 104 | } 105 | 106 | now = time(NULL); 107 | } 108 | 109 | for (int i = 0; checks[i].match != NULL; i++) { 110 | if (checks[i].matched == false) goto done; 111 | } 112 | 113 | ret = 0; 114 | 115 | done: 116 | if (out) fclose(out); 117 | return ret; 118 | } 119 | 120 | int child(int outpipe[]) 121 | { 122 | int ret; 123 | 124 | ret = mock_activation_environment(); 125 | if (ret) exit(EXIT_FAILURE); 126 | 127 | close(outpipe[0]); 128 | ret = dup2(outpipe[1], 2); 129 | if (ret == -1) exit(EXIT_FAILURE); 130 | 131 | execv("./gssproxy", srv_args); 132 | exit(EXIT_FAILURE); 133 | } 134 | 135 | int main(int argc, const char *main_argv[]) 136 | { 137 | pid_t proxy, w; 138 | int outpipe[2]; 139 | int ret; 140 | 141 | fprintf(stderr, "Test userproxy mode: "); 142 | 143 | ret = mock_activation_sockets(); 144 | if (ret) { 145 | ret = EXIT_FAILURE; 146 | goto done; 147 | } 148 | 149 | ret = pipe(outpipe); 150 | if (ret) { 151 | ret = EXIT_FAILURE; 152 | goto done; 153 | } 154 | 155 | proxy = fork(); 156 | if (proxy == -1) { 157 | ret = EXIT_FAILURE; 158 | goto done; 159 | } 160 | 161 | if (proxy == 0) { 162 | child(outpipe); 163 | } 164 | 165 | close(outpipe[1]); 166 | 167 | ret = wait_and_check_output(outpipe[0], 6); 168 | if (ret) { 169 | ret = EXIT_FAILURE; 170 | goto done; 171 | } 172 | 173 | w = waitpid(-1, &ret, WNOHANG); 174 | if (w != proxy || ret != 0) { 175 | ret = EXIT_FAILURE; 176 | goto done; 177 | } 178 | 179 | ret = 0; 180 | 181 | done: 182 | if (ret) { 183 | fprintf(stderr, "FAIL\n"); 184 | fflush(stderr); 185 | return ret; 186 | } 187 | 188 | fprintf(stderr, "SUCCESS\n"); 189 | fflush(stderr); 190 | return 0; 191 | } 192 | -------------------------------------------------------------------------------- /x-files/gp_rpc.x: -------------------------------------------------------------------------------- 1 | /* 2 | * ONC RPC request/reply header XDR. 3 | * 4 | * Note that this XDR is extracted from RFC1831 and massaged so that 5 | * rpcgen(1) accepts it, but it is intended to be wire-compatible with 6 | * RFC1831. 7 | * 8 | * Also, in order to avoid symbol naming conflicts, we prefix "gp_" and 9 | * "GP_" to all symbols from RFC1831. "GP" stands for "GSS proxy". 10 | */ 11 | 12 | enum gp_rpc_auth_flavor { 13 | GP_RPC_AUTH_NONE = 0, 14 | GP_RPC_AUTH_SYS = 1, 15 | GP_RPC_AUTH_SHORT = 2, 16 | GP_RPC_AUTH_DH = 3, 17 | GP_RPC_RPCSEC_GSS = 6 18 | /* and more to be defined */ 19 | }; 20 | 21 | struct gp_rpc_opaque_auth { 22 | gp_rpc_auth_flavor flavor; 23 | opaque body<400>; 24 | }; 25 | 26 | enum gp_rpc_msg_type { 27 | GP_RPC_CALL = 0, 28 | GP_RPC_REPLY = 1 29 | }; 30 | 31 | enum gp_rpc_reply_status { 32 | GP_RPC_MSG_ACCEPTED = 0, 33 | GP_RPC_MSG_DENIED = 1 34 | }; 35 | 36 | enum gp_rpc_accept_status { 37 | GP_RPC_SUCCESS = 0, /* RPC executed successfully */ 38 | GP_RPC_PROG_UNAVAIL = 1, /* remote hasn't exported program */ 39 | GP_RPC_PROG_MISMATCH = 2, /* remote can't support version # */ 40 | GP_RPC_PROC_UNAVAIL = 3, /* program can't support procedure */ 41 | GP_RPC_GARBAGE_ARGS = 4, /* procedure can't decode params */ 42 | GP_RPC_SYSTEM_ERR = 5 /* e.g. memory allocation failure */ 43 | }; 44 | 45 | enum gp_rpc_reject_status { 46 | GP_RPC_RPC_MISMATCH = 0, /* RPC version number != 2 */ 47 | GP_RPC_AUTH_ERROR = 1 /* remote can't authenticate caller */ 48 | }; 49 | 50 | enum gp_rpc_auth_status { 51 | GP_RPC_AUTH_OK = 0, /* success */ 52 | /* 53 | * failed at remote end 54 | */ 55 | GP_RPC_AUTH_BADCRED = 1, /* bad credential (seal broken) */ 56 | GP_RPC_AUTH_REJECTEDCRED = 2, /* client must begin new session */ 57 | GP_RPC_AUTH_BADVERF = 3, /* bad verifier (seal broken) */ 58 | GP_RPC_AUTH_REJECTEDVERF = 4, /* verifier expired or replayed */ 59 | GP_RPC_AUTH_TOOWEAK = 5, /* rejected for security reasons */ 60 | /* 61 | * failed locally 62 | */ 63 | GP_RPC_AUTH_INVALIDRESP = 6, /* bogus response verifier */ 64 | GP_RPC_AUTH_FAILED = 7, /* reason unknown */ 65 | /* 66 | * AUTH_KERB errors; deprecated. See [RFC2695] 67 | */ 68 | GP_RPC_AUTH_KERB_GENERIC = 8, /* kerberos generic error */ 69 | GP_RPC_AUTH_TIMEEXPIRE = 9, /* time of credential expired */ 70 | GP_RPC_AUTH_TKT_FILE = 10, /* problem with ticket file */ 71 | GP_RPC_AUTH_DECODE = 11, /* can't decode authenticator */ 72 | GP_RPC_AUTH_NET_ADDR = 12, /* wrong net address in ticket */ 73 | /* 74 | * RPCSEC_GSS GSS related errors 75 | */ 76 | GP_RPC_RPCSEC_GSS_CREDPROBLEM = 13, /* no credentials for user */ 77 | GP_RPC_RPCSEC_GSS_CTXPROBLEM = 14 /* problem with context */ 78 | }; 79 | 80 | struct gp_rpc_mismatch_info { 81 | unsigned int low; 82 | unsigned int high; 83 | }; 84 | 85 | union gp_rpc_reply_union switch (gp_rpc_accept_status status) { 86 | case GP_RPC_SUCCESS: 87 | opaque results[0]; 88 | /* 89 | * procedure-specific results start here 90 | */ 91 | case GP_RPC_PROG_MISMATCH: 92 | gp_rpc_mismatch_info mismatch_info; 93 | default: 94 | /* 95 | * Void. Cases include PROG_UNAVAIL, PROC_UNAVAIL, 96 | * GARBAGE_ARGS, and SYSTEM_ERR. 97 | */ 98 | void; 99 | }; 100 | 101 | struct gp_rpc_accepted_reply { 102 | gp_rpc_opaque_auth verf; 103 | gp_rpc_reply_union reply_data; 104 | }; 105 | 106 | union gp_rpc_rejected_reply switch (gp_rpc_reject_status status) { 107 | case GP_RPC_RPC_MISMATCH: 108 | gp_rpc_mismatch_info mismatch_info; 109 | case GP_RPC_AUTH_ERROR: 110 | gp_rpc_auth_status status; 111 | }; 112 | struct gp_rpc_call_header { 113 | unsigned int rpcvers; /* must be equal to two (2) */ 114 | unsigned int prog; 115 | unsigned int vers; 116 | unsigned int proc; 117 | gp_rpc_opaque_auth cred; 118 | gp_rpc_opaque_auth verf; 119 | /* procedure-specific parameters start here */ 120 | }; 121 | 122 | union gp_rpc_reply_header switch (gp_rpc_reply_status status) { 123 | case GP_RPC_MSG_ACCEPTED: 124 | gp_rpc_accepted_reply accepted; 125 | case GP_RPC_MSG_DENIED: 126 | gp_rpc_rejected_reply rejected; 127 | }; 128 | 129 | union gp_rpc_msg_union switch (gp_rpc_msg_type type) { 130 | case GP_RPC_CALL: 131 | gp_rpc_call_header chdr; 132 | case GP_RPC_REPLY: 133 | gp_rpc_reply_header rhdr; 134 | }; 135 | 136 | struct gp_rpc_msg { 137 | unsigned int xid; 138 | gp_rpc_msg_union header; 139 | }; 140 | 141 | -------------------------------------------------------------------------------- /src/gp_common.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #ifndef _GP_COMMON_H_ 4 | #define _GP_COMMON_H_ 5 | 6 | #include "config.h" 7 | #include "gp_debug.h" 8 | #include "gp_log.h" 9 | 10 | #define no_const(ptr) ((void *)((uintptr_t)(ptr))) 11 | #define UNUSED __attribute__((unused)) 12 | 13 | /* add element to list head */ 14 | #define LIST_ADD(list, elem) do { \ 15 | elem->prev = NULL; \ 16 | elem->next = list; \ 17 | if (list) { \ 18 | list->prev = elem; \ 19 | } \ 20 | list = elem; \ 21 | } while (0) 22 | 23 | /* remove element from list */ 24 | #define LIST_DEL(list, elem) do { \ 25 | if (elem->next) { \ 26 | elem->next->prev = elem->prev; \ 27 | } \ 28 | if (elem->prev) { \ 29 | elem->prev->next = elem->next; \ 30 | } \ 31 | if (list == elem) { \ 32 | list = elem->next; \ 33 | } \ 34 | elem->prev = NULL; \ 35 | elem->next = NULL; \ 36 | } while (0) 37 | 38 | #define safefree(ptr) do { \ 39 | free(no_const(ptr)); \ 40 | ptr = NULL; \ 41 | } while(0) 42 | 43 | #define GPKRB_SRV_NAME "Encrypted/Credentials/v1@X-GSSPROXY:" 44 | #define ENC_MIN_PAD_LEN 8 45 | 46 | /* max out at 1MB for now */ 47 | #define MAX_RPC_SIZE 1024*1024 48 | 49 | #ifdef HAVE_SYSTEMD_DAEMON 50 | #include 51 | #else 52 | __inline__ int sd_notifyf(int unset_environment UNUSED, const char *format UNUSED, ...) 53 | { 54 | return 0; 55 | } 56 | #endif 57 | 58 | uint64_t time_now_usec(void); 59 | bool gp_same(const char *a, const char *b); 60 | bool gp_boolean_is_true(const char *s); 61 | char *gp_getenv(const char *name); 62 | 63 | ssize_t gp_safe_read(int fd, void *buf, size_t count); 64 | ssize_t gp_safe_write(int fd, const void *buf, size_t count); 65 | /* NOTE: read the note in gp_util.c before using gp_strerror() */ 66 | char *gp_strerror(int errnum); 67 | 68 | #include "rpcgen/gss_proxy.h" 69 | 70 | union gp_rpc_arg { 71 | gssx_arg_release_handle release_handle; 72 | gssx_arg_indicate_mechs indicate_mechs; 73 | gssx_arg_import_and_canon_name import_and_canon_name; 74 | gssx_arg_get_call_context get_call_context; 75 | gssx_arg_acquire_cred acquire_cred; 76 | gssx_arg_export_cred export_cred; 77 | gssx_arg_import_cred import_cred; 78 | gssx_arg_store_cred store_cred; 79 | gssx_arg_init_sec_context init_sec_context; 80 | gssx_arg_accept_sec_context accept_sec_context; 81 | gssx_arg_get_mic get_mic; 82 | gssx_arg_verify_mic verify_mic; 83 | gssx_arg_wrap wrap; 84 | gssx_arg_unwrap unwrap; 85 | gssx_arg_wrap_size_limit wrap_size_limit; 86 | }; 87 | 88 | union gp_rpc_res { 89 | gssx_res_release_handle release_handle; 90 | gssx_res_indicate_mechs indicate_mechs; 91 | gssx_res_import_and_canon_name import_and_canon_name; 92 | gssx_res_get_call_context get_call_context; 93 | gssx_res_acquire_cred acquire_cred; 94 | gssx_res_export_cred export_cred; 95 | gssx_res_import_cred import_cred; 96 | gssx_res_store_cred store_cred; 97 | gssx_res_init_sec_context init_sec_context; 98 | gssx_res_accept_sec_context accept_sec_context; 99 | gssx_res_get_mic get_mic; 100 | gssx_res_verify_mic verify_mic; 101 | gssx_res_wrap wrap; 102 | gssx_res_unwrap unwrap; 103 | gssx_res_wrap_size_limit wrap_size_limit; 104 | }; 105 | 106 | #define gpopt_string_match(buf, val, len) \ 107 | (len == (buf)->octet_string_len && \ 108 | strncmp((val), (buf)->octet_string_val, \ 109 | (buf)->octet_string_len) == 0) 110 | 111 | #define gp_option_name_match(opt, val, len) \ 112 | gpopt_string_match(&((opt)->option), val, len) 113 | 114 | #define gp_option_value_match(opt, val, len) \ 115 | gpopt_string_match(&((opt)->value), val, len) 116 | 117 | #define gp_options_find(res, opts, name, len) \ 118 | do { \ 119 | struct gssx_option *_v; \ 120 | res = NULL; \ 121 | for (unsigned _o = 0; _o < opts.options_len; _o++) { \ 122 | _v = &opts.options_val[_o]; \ 123 | if (gp_option_name_match(_v, name, len)) { \ 124 | res = _v; \ 125 | break; \ 126 | } \ 127 | } \ 128 | } while(0) 129 | 130 | #define ACQUIRE_TYPE_OPTION "acquire_type" 131 | #define ACQUIRE_IMPERSONATE_NAME "impersonate_name" 132 | #define CRED_SYNC_OPTION "sync_modified_creds" 133 | #define CRED_SYNC_DEFAULT "default" 134 | #define CRED_SYNC_PAYLOAD "sync_creds" 135 | 136 | #define LOCALNAME_OPTION "localname" 137 | 138 | #define GPKRB_MAX_CRED_SIZE 1024 * 512 139 | 140 | uint32_t gp_add_option(gssx_option **options_val, u_int *options_len, 141 | const void *option, size_t option_len, 142 | const void *value, size_t value_len); 143 | 144 | #endif /* _GP_COMMON_H_ */ 145 | -------------------------------------------------------------------------------- /man/Makefile.am: -------------------------------------------------------------------------------- 1 | # The following variable is dependent on placement of this file 2 | top_builddir = .. 3 | 4 | ############ 5 | # MANPAGES # 6 | ############ 7 | 8 | #Special Rules: 9 | export SGML_CATALOG_FILES 10 | DOCBOOK_XSLT = http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl 11 | XMLLINT_FLAGS = --catalogs --postvalid --nonet --xinclude --noout 12 | XSLTPROC_FLAGS = --catalogs --xinclude --nonet 13 | 14 | man_MANS = \ 15 | gssproxy.8 gssproxy.conf.5 gssproxy-mech.8 16 | 17 | EXTRA_DIST = $(man_MANS:%=%.xml) $(wildcard $(srcdir)/include/*.xml) 18 | 19 | SUFFIXES = .1.xml .1 .3.xml .3 .5.xml .5 .8.xml .8 20 | .1.xml.1: 21 | $(XMLLINT) $(XMLLINT_FLAGS) $< 22 | $(XSLTPROC) -o $@ $(XSLTPROC_FLAGS) $(DOCBOOK_XSLT) $< 23 | 24 | .3.xml.3: 25 | $(XMLLINT) $(XMLLINT_FLAGS) $< 26 | $(XSLTPROC) -o $@ $(XSLTPROC_FLAGS) $(DOCBOOK_XSLT) $< 27 | 28 | .5.xml.5: 29 | $(XMLLINT) $(XMLLINT_FLAGS) $< 30 | $(XSLTPROC) -o $@ $(XSLTPROC_FLAGS) $(DOCBOOK_XSLT) $< 31 | 32 | .8.xml.8: 33 | $(XMLLINT) $(XMLLINT_FLAGS) $< 34 | $(XSLTPROC) -o $@ $(XSLTPROC_FLAGS) $(DOCBOOK_XSLT) $< 35 | 36 | clean-local: 37 | rm -f $(man_MANS) 38 | 39 | ######################## 40 | # MANPAGE TRANSLATIONS # 41 | ######################## 42 | # 43 | #PO4A=@PO4A@ 44 | #SED=@SED@ 45 | # 46 | #PACKAGE_DOC=gssproxy-docs 47 | # 48 | #POTFILE = po/$(PACKAGE_DOC).pot 49 | #PO4A_CONFIG = po/po4a.cfg 50 | # 51 | ## Extract the list of languages from the po4a config file. 52 | #LINGUAS_DIST = `$(SED) -ne 's/^.*\[po4a_langs\] \(.*\)$$/\1/p' $(srcdir)/$(PO4A_CONFIG)` 53 | # 54 | ## If the user has not defined it let's use the default. 55 | #LINGUAS ?= $(LINGUAS_DIST) 56 | # 57 | #PO4A_COMMON_OPTS = --option doctype=docbook \ 58 | # --package-name $(PACKAGE_DOC) \ 59 | # --variable builddir=$(CURDIR) \ 60 | # --package-version $(PACKAGE_VERSION) \ 61 | # --msgid-bugs-address simo@redhat.com \ 62 | # --copyright-holder "Red Hat" 63 | # 64 | #PO4A_BUILD_OPTS = $(PO4A_COMMON_OPTS) --no-backups 65 | # 66 | #EXTRA_DIST += \ 67 | # $(POTFILE)\ 68 | # $(PO4A_CONFIG) 69 | # 70 | #XML_DOC = $(wildcard $(srcdir)/*.xml) $(wildcard $(srcdir)/include/*.xml) 71 | # 72 | #if HAVE_PO4A 73 | # 74 | ## FIXME: Use a stamp file until po4a supports them internally. 75 | #man.stamp: $(XML_DOC) $(POTFILE) $(PO4A_CONFIG) 76 | # cd $(srcdir) && \ 77 | # $(PO4A) $(PO4A_BUILD_OPTS) $(PO4A_CONFIG) 78 | # touch $@ 79 | # 80 | #update-po: 81 | # cd $(srcdir) && \ 82 | # $(PO4A) $(PO4A_BUILD_OPTS) --force $(PO4A_CONFIG) 83 | # 84 | #dist-hook: man.stamp 85 | # if [ -f man.stamp ]; then \ 86 | # cp man.stamp $(distdir); \ 87 | # for lang in $(LINGUAS_DIST); do \ 88 | # cp $(srcdir)/po/$$lang.po $(distdir)/po; \ 89 | # $(mkdir_p) $(distdir)/$$lang; \ 90 | # cp -r $(builddir)/$$lang $(distdir)/; \ 91 | # done; \ 92 | # else \ 93 | # cp $(srcdir)/man.stamp $(distdir); \ 94 | # for lang in $(LINGUAS_DIST); do \ 95 | # cp $(srcdir)/po/$$lang.po $(distdir)/po; \ 96 | # $(mkdir_p) $(distdir)/$$lang; \ 97 | # cp -r $(srcdir)/$$lang $(distdir)/; \ 98 | # done; \ 99 | # fi 100 | # 101 | # 102 | #clean-local-no: 103 | #clean-local-yes: 104 | # for lang in $(LINGUAS); do \ 105 | # if [ -d $$lang ]; then \ 106 | # rm -rf $$lang; \ 107 | # fi \ 108 | # done 109 | # rm -f $(man_MANS) 110 | # rm -f man.stamp 111 | # 112 | #else 113 | # 114 | #man.stamp: $(XML_DOC) 115 | # touch $@ 116 | # 117 | #clean-local-no: 118 | #clean-local-yes: 119 | # rm -f $(man_MANS) 120 | # rm -f man.stamp 121 | # 122 | #endif 123 | # 124 | #clean-local: clean-local-@USE_NLS@ 125 | #distclean-local: clean-local-@USE_NLS@ 126 | #mostlyclean-local: clean-local-@USE_NLS@ 127 | #maintainer-clean-local: clean-local-@USE_NLS@ 128 | # 129 | ## Generate translated manual pages 130 | #all-local: all-local-@USE_NLS@ 131 | #all-local-no: 132 | #all-local-yes: man.stamp 133 | # if [ -z $$recursion ]; then \ 134 | # for lang in $(LINGUAS); do \ 135 | # if [ -d $$lang ]; then \ 136 | # sources=$$(ls -1 $$lang/*.xml); \ 137 | # manpages=$$(echo $$sources | $(SED) 's/\.xml//g'); \ 138 | # $(MAKE) recursion=1 man_MANS="$$manpages"; \ 139 | # fi \ 140 | # done \ 141 | # fi 142 | # 143 | #install-data-local: install-data-local-@USE_NLS@ 144 | #install-data-local-no: 145 | #install-data-local-yes: 146 | # for lang in $(LINGUAS); do \ 147 | # if [ -d $$lang ]; then \ 148 | # sources=$$(ls -1 $$lang/*.xml); \ 149 | # manpages=$$(echo $$sources | $(SED) 's/\.xml//g'); \ 150 | # $(MAKE) install-man \ 151 | # mandir="$(mandir)/$$lang" \ 152 | # man_MANS="$$manpages"; \ 153 | # fi \ 154 | # done 155 | # 156 | #uninstall-local: uninstall-local-@USE_NLS@ 157 | #uninstall-local-no: 158 | #uninstall-local-yes: 159 | # for lang in $(LINGUAS); do \ 160 | # if [ -d $$lang ]; then \ 161 | # sources=$$(ls -1 $$lang/*.xml); \ 162 | # manpages=$$(echo $$sources | $(SED) 's/\.xml//g'); \ 163 | # $(MAKE) uninstall-man \ 164 | # mandir="$(mandir)/$$lang" \ 165 | # man_MANS="$$manpages"; \ 166 | # fi \ 167 | # done 168 | -------------------------------------------------------------------------------- /tests/runtests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # Copyright (C) 2014,2015,2016 - GSS-Proxy contributors; see COPYING for the license. 3 | 4 | import argparse 5 | import importlib 6 | import signal 7 | import subprocess 8 | import sys 9 | import traceback 10 | 11 | import testlib 12 | from testlib import * 13 | 14 | def check_exec(name): 15 | env = {'PATH': '/sbin:/bin:/usr/sbin:/usr/bin:/usr/lib/mit/sbin'} 16 | ret = subprocess.call(["which", name], stdout=subprocess.DEVNULL, env=env) 17 | if ret != 0: 18 | print(f"Executable '{name}' not found in {env['PATH']}", 19 | file=sys.stderr) 20 | exit(1) 21 | 22 | def parse_args(): 23 | parser = argparse.ArgumentParser(description='GSS-Proxy Tests Environment') 24 | parser.add_argument('--path', default='%s/testdir' % os.getcwd(), 25 | help="Directory in which tests are run") 26 | parser.add_argument('--debug-all', default=False, action="store_true", 27 | help="Enable debugging for all test cases") 28 | parser.add_argument('--debug-gssproxy', default=False, action="store_true", 29 | help="Enable debugging for gssproxy command") 30 | parser.add_argument('--debug-cmd', default="gdb --args", 31 | help="Set the debugging command. Defaults to gdb " + 32 | "--args") 33 | parser.add_argument('--debug-num', default=-1, type=int, 34 | help="Specify the testcase number to debug") 35 | parser.add_argument('--timeout', default=30, type=int, 36 | help="Specify test case timeout limit") 37 | parser.add_argument('--valgrind-cmd', default="valgrind " + 38 | "--track-origins=yes", 39 | help="Set the valgrind command. Defaults to " + 40 | "valgrind --track-origins=yes") 41 | parser.add_argument('--force-valgrind', default=False, action="store_true", 42 | help="Force valgrind to be run on all test cases") 43 | 44 | args = vars(parser.parse_args()) 45 | testlib_process_args(args) 46 | 47 | return args 48 | 49 | def runtests_main(testfiles): 50 | args = parse_args() 51 | 52 | for e in ["bash", "pkg-config", "zcat", "kinit", "krb5kdc", "kdb5_util", 53 | "kadmin.local", "kdb5_ldap_util", "slapd", "slapadd", 54 | "ldapmodify", "valgrind"]: 55 | if e == "valgrind" and not args['valgrind_cmd'].startswith('valgrind'): 56 | continue 57 | 58 | check_exec(e) 59 | 60 | testdir = args['path'] 61 | if os.path.exists(testdir): 62 | shutil.rmtree(testdir) 63 | os.makedirs(testdir) 64 | 65 | processes = dict() 66 | 67 | errored = False 68 | 69 | try: 70 | wrapenv = setup_wrappers(testdir) 71 | write_ldap_krb5_config(testdir) 72 | 73 | ldapproc, ldapenv = setup_ldap(testdir, wrapenv) 74 | processes["LDAP(%d)" % ldapproc.pid] = ldapproc 75 | 76 | kdcproc, kdcenv = setup_kdc(testdir, wrapenv) 77 | processes['KDC(%d)' % kdcproc.pid] = kdcproc 78 | 79 | keysenv = setup_keys(testdir, kdcenv) 80 | 81 | gssapienv = setup_gssapi_env(testdir, kdcenv) 82 | 83 | if 'TERM' in os.environ: 84 | gssapienv['TERM'] = os.environ['TERM'] 85 | 86 | gssproxyenv = keysenv 87 | gssproxyenv['KRB5_TRACE'] = os.path.join(testdir, 'gssproxy.trace') 88 | 89 | gproc, gpsocket = setup_gssproxy(testdir, gssproxyenv) 90 | processes['GSS-Proxy(%d)' % gproc.pid] = gproc 91 | gssapienv['GSSPROXY_SOCKET'] = gpsocket 92 | 93 | basicconf = {'svc_name': "host@%s" % WRAP_HOSTNAME, 94 | 'keytab': os.path.join(testdir, SVC_KTNAME)} 95 | basicconf["gpid"] = gproc.pid 96 | basicconf["keysenv"] = keysenv 97 | 98 | print("Tests to be run: " + ", ".join(testfiles)) 99 | for f in testfiles: 100 | fmod = f[:-len(".py")] 101 | t = importlib.__import__(fmod) 102 | 103 | basicconf['prefix'] = str(testlib.cmd_index) 104 | basicconf['logpath'] = testdir 105 | r = t.run(testdir, gssapienv, basicconf) 106 | if r != 0: 107 | errored = True 108 | except Exception: 109 | traceback.print_exc() 110 | errored = True 111 | finally: 112 | for name in processes: 113 | print("Killing %s" % name) 114 | os.killpg(processes[name].pid, signal.SIGTERM) 115 | 116 | if errored: 117 | sys.exit(1) 118 | sys.exit(0) 119 | 120 | if __name__ == "__main__": 121 | print("\n") 122 | print("To pass arguments to the test suite, use CHECKARGS:") 123 | print(" make check CHECKARGS='--debug-num='") 124 | print("A full set of available options can be seen with --help") 125 | print("\n") 126 | 127 | testfiles = [f for f in os.listdir(os.path.dirname(sys.argv[0])) \ 128 | if f.endswith(".py") and f.startswith("t_")] 129 | testfiles.sort() 130 | runtests_main(testfiles) 131 | -------------------------------------------------------------------------------- /src/client/gpm_accept_sec_context.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "gssapi_gpm.h" 4 | #include "src/gp_conv.h" 5 | 6 | OM_uint32 gpm_accept_sec_context(OM_uint32 *minor_status, 7 | gssx_ctx **context_handle, 8 | gssx_cred *acceptor_cred_handle, 9 | gss_buffer_t input_token_buffer, 10 | gss_channel_bindings_t input_chan_bindings, 11 | gssx_name **src_name, 12 | gss_OID *mech_type, 13 | gss_buffer_t output_token, 14 | OM_uint32 *ret_flags, 15 | OM_uint32 *time_rec, 16 | gssx_cred **delegated_cred_handle) 17 | { 18 | union gp_rpc_arg uarg; 19 | union gp_rpc_res ures; 20 | gssx_arg_accept_sec_context *arg = &uarg.accept_sec_context; 21 | gssx_res_accept_sec_context *res = &ures.accept_sec_context; 22 | gssx_ctx *ctx = NULL; 23 | gssx_name *name = NULL; 24 | gss_buffer_t outbuf = NULL; 25 | uint32_t ret_maj; 26 | int ret; 27 | 28 | memset(&uarg, 0, sizeof(union gp_rpc_arg)); 29 | memset(&ures, 0, sizeof(union gp_rpc_res)); 30 | 31 | /* prepare proxy request */ 32 | if (*context_handle) { 33 | arg->context_handle = *context_handle; 34 | } 35 | 36 | if (acceptor_cred_handle) { 37 | arg->cred_handle = acceptor_cred_handle; 38 | } 39 | 40 | ret = gp_conv_buffer_to_gssx(input_token_buffer, &arg->input_token); 41 | if (ret) { 42 | goto done; 43 | } 44 | 45 | if (input_chan_bindings) { 46 | ret = gp_conv_cb_to_gssx_alloc(input_chan_bindings, &arg->input_cb); 47 | if (ret) { 48 | goto done; 49 | } 50 | } 51 | 52 | /* check if we want delegated creds */ 53 | if (delegated_cred_handle) { 54 | arg->ret_deleg_cred = true; 55 | } 56 | 57 | /* execute proxy request */ 58 | ret = gpm_make_call(GSSX_ACCEPT_SEC_CONTEXT, &uarg, &ures); 59 | if (ret) { 60 | goto done; 61 | } 62 | 63 | /* return values */ 64 | if (res->status.major_status) { 65 | gpm_save_status(&res->status); 66 | ret_maj = res->status.major_status; 67 | *minor_status = res->status.minor_status; 68 | ret = 0; 69 | goto done; 70 | } 71 | 72 | ctx = res->context_handle; 73 | /* we are stealing the delegated creds on success, so we do not want 74 | * it to be freed by xdr_free */ 75 | res->context_handle = NULL; 76 | if (ctx == NULL) { 77 | ret = EINVAL; 78 | goto done; 79 | } 80 | 81 | if (src_name) { 82 | ret = gp_copy_gssx_name_alloc(&ctx->src_name, &name); 83 | if (ret) { 84 | goto done; 85 | } 86 | } 87 | 88 | ret = gp_conv_gssx_to_buffer_alloc(res->output_token, &outbuf); 89 | if (ret) { 90 | goto done; 91 | } 92 | 93 | if (mech_type) { 94 | gss_OID_desc mech; 95 | gp_conv_gssx_to_oid(&res->status.mech, &mech); 96 | ret = gpm_mech_to_static(&mech, mech_type); 97 | if (ret) { 98 | goto done; 99 | } 100 | } 101 | 102 | if (src_name) { 103 | *src_name = name; 104 | } 105 | if (outbuf) { 106 | *output_token = *outbuf; 107 | free(outbuf); 108 | outbuf = NULL; 109 | } 110 | if (ret_flags) { 111 | *ret_flags = ctx->ctx_flags; 112 | } 113 | if (time_rec) { 114 | *time_rec = ctx->lifetime; 115 | } 116 | 117 | if (res->delegated_cred_handle) { 118 | if (delegated_cred_handle) { 119 | *delegated_cred_handle = res->delegated_cred_handle; 120 | } 121 | /* we are stealing the delegated creds on success, so we do not want 122 | * it to be freed by xdr_free */ 123 | res->delegated_cred_handle = NULL; 124 | } 125 | 126 | *minor_status = 0; 127 | ret_maj = GSS_S_COMPLETE; 128 | 129 | done: 130 | /* we are putting our copy of these structures in here, 131 | * and do not want it to be freed by xdr_free */ 132 | arg->context_handle = NULL; 133 | arg->cred_handle = NULL; 134 | gpm_free_xdrs(GSSX_ACCEPT_SEC_CONTEXT, &uarg, &ures); 135 | 136 | if (ret) { 137 | if (ctx) { 138 | xdr_free((xdrproc_t)xdr_gssx_ctx, (char *)ctx); 139 | free(ctx); 140 | } 141 | if (name) { 142 | xdr_free((xdrproc_t)xdr_gssx_name, (char *)name); 143 | free(name); 144 | } 145 | if (outbuf) { 146 | free(outbuf->value); 147 | free(outbuf); 148 | } 149 | *minor_status = ret; 150 | return GSS_S_FAILURE; 151 | } 152 | 153 | /* always replace old ctx handle and set new */ 154 | if (*context_handle) { 155 | xdr_free((xdrproc_t)xdr_gssx_ctx, (char *)*context_handle); 156 | free(*context_handle); 157 | } 158 | *context_handle = ctx; 159 | 160 | return ret_maj; 161 | } 162 | 163 | -------------------------------------------------------------------------------- /tests/t_acquire.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 the GSS-PROXY contributors, see COPYING for license */ 2 | 3 | #include "t_utils.h" 4 | #include 5 | 6 | int main(int argc, const char *argv[]) 7 | { 8 | gss_cred_id_t cred_handle = GSS_C_NO_CREDENTIAL; 9 | gss_ctx_id_t init_ctx = GSS_C_NO_CONTEXT; 10 | gss_ctx_id_t accept_ctx = GSS_C_NO_CONTEXT; 11 | gss_buffer_desc in_token = GSS_C_EMPTY_BUFFER; 12 | gss_buffer_desc out_token = GSS_C_EMPTY_BUFFER; 13 | gss_name_t target_name; 14 | gss_OID_set_desc oid_set = { 1, discard_const(gss_mech_krb5) }; 15 | uint32_t ret_maj; 16 | uint32_t ret_min; 17 | int ret = -1; 18 | 19 | if (argc != 2) return -1; 20 | 21 | ret = t_string_to_name(argv[1], &target_name, 22 | GSS_C_NT_HOSTBASED_SERVICE); 23 | if (ret) { 24 | DEBUG("Failed to import server name from argv[1]\n"); 25 | ret = -1; 26 | goto done; 27 | } 28 | 29 | ret_maj = gss_acquire_cred(&ret_min, 30 | GSS_C_NO_NAME, 31 | GSS_C_INDEFINITE, 32 | &oid_set, 33 | GSS_C_INITIATE, 34 | &cred_handle, 35 | NULL, NULL); 36 | if (ret_maj != GSS_S_COMPLETE) { 37 | DEBUG("gss_acquire_cred() failed\n"); 38 | t_log_failure(GSS_C_NO_OID, ret_maj, ret_min); 39 | ret = -1; 40 | goto done; 41 | } 42 | 43 | ret_maj = gss_store_cred(&ret_min, cred_handle, GSS_C_INITIATE, 44 | GSS_C_NULL_OID, 1, 1, NULL, NULL); 45 | if (ret_maj) { 46 | DEBUG("Error saving credentials\n"); 47 | t_log_failure(GSS_C_NO_OID, ret_maj, ret_min); 48 | ret = -1; 49 | goto done; 50 | } 51 | 52 | gss_release_cred(&ret_min, &cred_handle); 53 | 54 | ret_maj = gss_init_sec_context(&ret_min, 55 | GSS_C_NO_CREDENTIAL, 56 | &init_ctx, 57 | target_name, 58 | GSS_C_NO_OID, 59 | GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG, 60 | 0, 61 | GSS_C_NO_CHANNEL_BINDINGS, 62 | &in_token, 63 | NULL, 64 | &out_token, 65 | NULL, 66 | NULL); 67 | if (ret_maj != GSS_S_CONTINUE_NEEDED) { 68 | DEBUG("gss_init_sec_context() failed\n"); 69 | t_log_failure(GSS_C_NO_OID, ret_maj, ret_min); 70 | ret = -1; 71 | goto done; 72 | } 73 | 74 | /* We get stuff from stdin and spit it out on stderr */ 75 | if (!out_token.length) { 76 | DEBUG("No output token ?"); 77 | ret = -1; 78 | goto done; 79 | } 80 | 81 | 82 | /* in/out token inverted here intentionally */ 83 | ret_maj = gss_accept_sec_context(&ret_min, 84 | &accept_ctx, 85 | GSS_C_NO_CREDENTIAL, 86 | &out_token, 87 | GSS_C_NO_CHANNEL_BINDINGS, 88 | NULL, 89 | NULL, 90 | &in_token, 91 | NULL, 92 | NULL, 93 | NULL); 94 | if (ret_maj) { 95 | DEBUG("Error accepting context\n"); 96 | t_log_failure(GSS_C_NO_OID, ret_maj, ret_min); 97 | ret = -1; 98 | goto done; 99 | } 100 | 101 | if (!in_token.length) { 102 | DEBUG("No output token ?"); 103 | ret = -1; 104 | goto done; 105 | } 106 | 107 | gss_release_buffer(&ret_min, &out_token); 108 | 109 | ret_maj = gss_init_sec_context(&ret_min, 110 | GSS_C_NO_CREDENTIAL, 111 | &init_ctx, 112 | target_name, 113 | GSS_C_NO_OID, 114 | GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG, 115 | 0, 116 | GSS_C_NO_CHANNEL_BINDINGS, 117 | &in_token, 118 | NULL, 119 | &out_token, 120 | NULL, 121 | NULL); 122 | if (ret_maj) { 123 | DEBUG("Error initializing context\n"); 124 | t_log_failure(GSS_C_NO_OID, ret_maj, ret_min); 125 | ret = -1; 126 | goto done; 127 | } 128 | 129 | ret = 0; 130 | 131 | done: 132 | gss_release_buffer(&ret_min, &in_token); 133 | gss_release_buffer(&ret_min, &out_token); 134 | gss_release_cred(&ret_min, &cred_handle); 135 | gss_release_name(&ret_min, &target_name); 136 | gss_delete_sec_context(&ret_min, &init_ctx, GSS_C_NO_BUFFER); 137 | gss_delete_sec_context(&ret_min, &accept_ctx, GSS_C_NO_BUFFER); 138 | return ret; 139 | } 140 | -------------------------------------------------------------------------------- /tests/t_impersonate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # Copyright (C) 2015,2016 - GSS-Proxy contributors; see COPYING for the license 3 | 4 | from testlib import * 5 | 6 | IMPERSONATE_CONF_TEMPLATE = ''' 7 | [gssproxy] 8 | debug_level = 2 9 | 10 | [service/impersonate] 11 | socket = ${TESTDIR}/impersonate.socket 12 | mechs = krb5 13 | cred_store = keytab:${GSSPROXY_KEYTAB} 14 | cred_store = client_keytab:${GSSPROXY_CLIENT_KEYTAB} 15 | allow_protocol_transition = yes 16 | allow_constrained_delegation = yes 17 | euid = ${UIDNUMBER} 18 | 19 | [service/selfonly] 20 | socket = ${TESTDIR}/impersonate-selfonly.socket 21 | mechs = krb5 22 | cred_store = keytab:${GSSPROXY_KEYTAB} 23 | cred_store = client_keytab:${GSSPROXY_CLIENT_KEYTAB} 24 | allow_protocol_transition = yes 25 | euid = ${UIDNUMBER} 26 | 27 | [service/proxyonly] 28 | socket = ${TESTDIR}/impersonate-proxyonly.socket 29 | mechs = krb5 30 | cred_store = keytab:${GSSPROXY_KEYTAB} 31 | cred_store = client_keytab:${GSSPROXY_CLIENT_KEYTAB} 32 | allow_constrained_delegation = yes 33 | euid = ${UIDNUMBER} 34 | 35 | ''' 36 | 37 | def run_cmd(testdir, env, conf, name, socket, cmd, keytab, expected_failure): 38 | conf['prefix'] = str(cmd_index) 39 | testenv = env.copy() 40 | testenv.update({'KRB5CCNAME': os.path.join(testdir, 't' + conf['prefix'] + 41 | '_impersonate.ccache'), 42 | 'KRB5_KTNAME': os.path.join(testdir, keytab), 43 | 'KRB5_TRACE': os.path.join(testdir, 't' + conf['prefix'] + 44 | '_impersonate.trace'), 45 | 'GSS_USE_PROXY': 'yes', 46 | 'GSSPROXY_SOCKET': socket, 47 | 'GSSPROXY_BEHAVIOR': 'REMOTE_FIRST'}) 48 | 49 | return run_testcase_cmd(testenv, conf, cmd, name, expected_failure) 50 | 51 | def run(testdir, env, conf): 52 | print("Testing impersonate creds...", file=sys.stderr) 53 | path_prefix = os.path.join(testdir, 't' + conf['prefix'] + '_') 54 | 55 | # Change gssproxy conf for our test 56 | keysenv = conf["keysenv"].copy() 57 | keysenv['KRB5_KTNAME'] = os.path.join(testdir, PROXY_KTNAME) 58 | update_gssproxy_conf(testdir, keysenv, IMPERSONATE_CONF_TEMPLATE) 59 | gssproxy_reload(testdir, conf['gpid']) 60 | 61 | rets = [] 62 | 63 | # Test all permitted 64 | msg = "Impersonate" 65 | socket = os.path.join(testdir, 'impersonate.socket') 66 | cmd = " ".join(["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS, 67 | path_prefix + 'impersonate.cache']) 68 | r = run_cmd(testdir, env, conf, msg, socket, cmd, PROXY_KTNAME, False) 69 | rets.append(r) 70 | 71 | #Test self fail 72 | msg = "Impersonate fail self" 73 | socket = os.path.join(testdir, 'impersonate-proxyonly.socket') 74 | cmd = " ".join(["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS, 75 | path_prefix + 'impersonate.cache']) 76 | r = run_cmd(testdir, env, conf, msg, socket, cmd, PROXY_KTNAME, True) 77 | rets.append(r) 78 | 79 | #Test proxy fail 80 | msg = "Impersonate fail proxy" 81 | socket = os.path.join(testdir, 'impersonate-selfonly.socket') 82 | cmd = " ".join(["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS, 83 | path_prefix + 'impersonate.cache']) 84 | r = run_cmd(testdir, env, conf, msg, socket, cmd, PROXY_KTNAME, True) 85 | rets.append(r) 86 | 87 | #Test s4u2self half succeed 88 | msg = "s4u2self delegation" 89 | socket = os.path.join(testdir, 'impersonate-selfonly.socket') 90 | cmd = " ".join(["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS, 91 | path_prefix + 'impersonate.cache', 's4u2self']) 92 | r = run_cmd(testdir, env, conf, msg, socket, cmd, PROXY_KTNAME, False) 93 | rets.append(r) 94 | 95 | #Test proxy to self succeed 96 | msg = "Impersonate to self" 97 | socket = os.path.join(testdir, 'impersonate-selfonly.socket') 98 | cmd = " ".join(["./tests/t_impersonate", USR_NAME, HOST_GSS, HOST_GSS, 99 | path_prefix + 'impersonate.cache', 's4u2proxy']) 100 | r = run_cmd(testdir, env, conf, msg, socket, cmd, SVC_KTNAME, False) 101 | rets.append(r) 102 | 103 | #Test s4u2proxy half fail 104 | msg = "s4u2proxy fail" 105 | socket = os.path.join(testdir, 'impersonate-selfonly.socket') 106 | cmd = " ".join(["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS, 107 | path_prefix + 'impersonate.cache', 's4u2proxy']) 108 | r = run_cmd(testdir, env, conf, msg, socket, cmd, PROXY_KTNAME, True) 109 | rets.append(r) 110 | 111 | #Test s4u2proxy half succeed 112 | msg = "s4u2proxy" 113 | socket = os.path.join(testdir, 'impersonate-proxyonly.socket') 114 | cmd = " ".join(["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS, 115 | path_prefix + 'impersonate.cache', 's4u2proxy']) 116 | r = run_cmd(testdir, env, conf, msg, socket, cmd, PROXY_KTNAME, False) 117 | rets.append(r) 118 | 119 | # Reset back gssproxy conf 120 | update_gssproxy_conf(testdir, keysenv, GSSPROXY_CONF_TEMPLATE) 121 | gssproxy_reload(testdir, conf['gpid']) 122 | 123 | e = [r for r in rets if r != 0] 124 | if len(e) > 0: 125 | return e[0] 126 | return 0 127 | 128 | if __name__ == "__main__": 129 | from runtests import runtests_main 130 | runtests_main(["t_impersonate.py"]) 131 | --------------------------------------------------------------------------------