1 From 0e04be2c1398dac40c50910a59157eed0ad5a7e4 Mon Sep 17 00:00:00 2001
2 From: Simo Sorce <simo@redhat.com>
3 Date: Tue, 14 Mar 2017 10:43:17 -0400
4 Subject: [PATCH] Allow connection to self when impersonator set
6 If the target of a context establishment is the impersonator itself,
7 then allow it. This kind of context establishment is used by tools like
8 mod_auth_gssapi to be able to inspect the ticket just obtained via
9 impersonation and it is basically a noop as the acceptor and the
10 impersonator are the same entitiy.
12 Signed-off-by: Simo Sorce <simo@redhat.com>
13 Reviewed-by: Robbie Harwood <rharwood@redhat.com>
15 (cherry picked from commit eada55e831d12b42d3be3a555ff4e133bed7f594)
17 proxy/src/gp_creds.c | 57 +++++++++++++++++++++++++----
18 proxy/src/gp_rpc_creds.h | 3 +-
19 proxy/src/gp_rpc_init_sec_context.c | 2 +-
20 proxy/tests/t_impersonate.py | 35 +++++++++++++-----
21 4 files changed, 78 insertions(+), 19 deletions(-)
23 diff --git a/proxy/src/gp_creds.c b/proxy/src/gp_creds.c
24 index 95a1c48..7d89b06 100644
25 --- a/proxy/src/gp_creds.c
26 +++ b/proxy/src/gp_creds.c
27 @@ -883,7 +883,8 @@ static uint32_t get_impersonator_name(uint32_t *min, gss_cred_id_t cred,
29 } else if (ret_maj == GSS_S_UNAVAILABLE) {
30 /* Not supported by krb5 library yet, fallback to raw krb5 calls */
31 - /* TODO: Remove once we set a required dependency on MIT 1.15+ */
32 + /* TODO: Remove once we set a minimum required dependency on a
33 + * release that supports this call */
34 ret_maj = get_impersonator_fallback(&ret_min, cred, impersonator);
35 if (ret_maj == GSS_S_FAILURE) {
36 if (ret_min == KRB5_CC_NOTFOUND) {
37 @@ -899,9 +900,47 @@ done:
41 +static uint32_t check_impersonator_name(uint32_t *min,
42 + gss_name_t target_name,
43 + const char *impersonator)
45 + gss_name_t canon_name = NULL;
46 + gss_buffer_desc buf;
47 + uint32_t ret_maj = 0;
48 + uint32_t ret_min = 0;
52 + ret_maj = gss_canonicalize_name(&discard, target_name, &gp_mech_krb5,
54 + if (ret_maj != GSS_S_COMPLETE) {
59 + ret_maj = gss_display_name(&discard, canon_name, &buf, NULL);
60 + gss_release_name(&discard, &canon_name);
61 + if (ret_maj != GSS_S_COMPLETE) {
66 + match = (strncmp(impersonator, buf.value, buf.length) == 0) &&
67 + (strlen(impersonator) == buf.length);
68 + gss_release_buffer(&discard, &buf);
72 + return GSS_S_COMPLETE;
74 + return GSS_S_UNAUTHORIZED;
78 uint32_t gp_cred_allowed(uint32_t *min,
79 struct gp_call_ctx *gpcall,
82 + gss_name_t target_name)
84 char *impersonator = NULL;
86 @@ -924,11 +963,11 @@ uint32_t gp_cred_allowed(uint32_t *min,
87 if (ret_maj) goto done;
89 /* if we find an impersonator entry we bail as that is not authorized,
90 - * if it were then gpcall->service->allow_const_deleg would have caused
91 - * the ealier check to return GSS_S_COMPLETE already */
92 + * *unless* the target is the impersonator itself! If the operation
93 + * were authorized then gpcall->service->allow_const_deleg would have
94 + * caused the ealier check to return GSS_S_COMPLETE already */
95 if (impersonator != NULL) {
97 - ret_maj = GSS_S_UNAUTHORIZED;
98 + ret_maj = check_impersonator_name(&ret_min, target_name, impersonator);
102 @@ -937,7 +976,11 @@ done:
103 GPDEBUGN(2, "Unauthorized impersonator credentials detected\n");
106 - GPDEBUGN(2, "No impersonator credentials detected\n");
107 + if (impersonator) {
108 + GPDEBUGN(2, "Credentials allowed for 'self'\n");
110 + GPDEBUGN(2, "No impersonator credentials detected\n");
114 GPDEBUG("Failure while checking credentials\n");
115 diff --git a/proxy/src/gp_rpc_creds.h b/proxy/src/gp_rpc_creds.h
116 index 54fe482..c116e53 100644
117 --- a/proxy/src/gp_rpc_creds.h
118 +++ b/proxy/src/gp_rpc_creds.h
119 @@ -34,7 +34,8 @@ uint32_t gp_add_krb5_creds(uint32_t *min,
121 uint32_t gp_cred_allowed(uint32_t *min,
122 struct gp_call_ctx *gpcall,
123 - gss_cred_id_t cred);
124 + gss_cred_id_t cred,
125 + gss_name_t target_name);
127 void gp_filter_flags(struct gp_call_ctx *gpcall, uint32_t *flags);
129 diff --git a/proxy/src/gp_rpc_init_sec_context.c b/proxy/src/gp_rpc_init_sec_context.c
130 index 767a3ff..413e2ec 100644
131 --- a/proxy/src/gp_rpc_init_sec_context.c
132 +++ b/proxy/src/gp_rpc_init_sec_context.c
133 @@ -108,7 +108,7 @@ int gp_init_sec_context(struct gp_call_ctx *gpcall,
137 - ret_maj = gp_cred_allowed(&ret_min, gpcall, ich);
138 + ret_maj = gp_cred_allowed(&ret_min, gpcall, ich, target_name);
142 diff --git a/proxy/tests/t_impersonate.py b/proxy/tests/t_impersonate.py
143 index 3e25962..29f9a41 100755
144 --- a/proxy/tests/t_impersonate.py
145 +++ b/proxy/tests/t_impersonate.py
146 @@ -34,19 +34,20 @@ IMPERSONATE_CONF_TEMPLATE = '''
150 -def run_cmd(testdir, env, conf, name, socket, cmd, expected_failure):
151 +def run_cmd(testdir, env, conf, name, socket, cmd, keytab, expected_failure):
153 logfile = conf['logfile']
155 testenv.update({'KRB5CCNAME': os.path.join(testdir, 't' + conf['prefix'] +
156 '_impersonate.ccache'),
157 - 'KRB5_KTNAME': os.path.join(testdir, PROXY_KTNAME),
158 + 'KRB5_KTNAME': os.path.join(testdir, keytab),
159 'KRB5_TRACE': os.path.join(testdir, 't' + conf['prefix'] +
160 '_impersonate.trace'),
161 'GSS_USE_PROXY': 'yes',
162 'GSSPROXY_SOCKET': socket,
163 'GSSPROXY_BEHAVIOR': 'REMOTE_FIRST'})
165 + print("\nTesting: [%s]" % (name,), file=logfile)
166 print("[COMMAND]\n%s\n[ENVIRONMENT]\n%s\n" % (cmd, testenv), file=logfile)
169 @@ -74,45 +75,59 @@ def run(testdir, env, conf):
173 + msg = "Impersonate"
174 socket = os.path.join(testdir, 'impersonate.socket')
175 cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS,
176 path_prefix + 'impersonate.cache']
177 - r = run_cmd(testdir, env, conf, "Impersonate", socket, cmd, False)
178 + r = run_cmd(testdir, env, conf, msg, socket, cmd, PROXY_KTNAME, False)
183 + msg = "Impersonate fail self"
184 socket = os.path.join(testdir, 'impersonate-proxyonly.socket')
185 cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS,
186 path_prefix + 'impersonate.cache']
187 - r = run_cmd(testdir, env, conf, "Impersonate fail self", socket, cmd, True)
188 + r = run_cmd(testdir, env, conf, msg, socket, cmd, PROXY_KTNAME, True)
193 + msg = "Impersonate fail proxy"
194 socket = os.path.join(testdir, 'impersonate-selfonly.socket')
195 cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS,
196 path_prefix + 'impersonate.cache']
197 - r = run_cmd(testdir, env, conf, "Impersonate fail proxy", socket, cmd, True)
198 + r = run_cmd(testdir, env, conf, msg, socket, cmd, PROXY_KTNAME, True)
201 #Test s4u2self half succeed
202 + msg = "s4u2self delegation"
203 socket = os.path.join(testdir, 'impersonate-selfonly.socket')
204 cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS,
205 path_prefix + 'impersonate.cache', 's4u2self']
206 - r = run_cmd(testdir, env, conf, "s4u2self delegation", socket, cmd, False)
207 + r = run_cmd(testdir, env, conf, msg, socket, cmd, PROXY_KTNAME, False)
210 + #Test proxy to self succeed
211 + msg = "Impersonate to self"
212 + socket = os.path.join(testdir, 'impersonate-selfonly.socket')
213 + cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, HOST_GSS,
214 + path_prefix + 'impersonate.cache', 's4u2proxy']
215 + r = run_cmd(testdir, env, conf, msg, socket, cmd, SVC_KTNAME, False)
218 #Test s4u2proxy half fail
219 + msg = "s4u2proxy fail"
220 socket = os.path.join(testdir, 'impersonate-selfonly.socket')
221 cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS,
222 path_prefix + 'impersonate.cache', 's4u2proxy']
223 - r = run_cmd(testdir, env, conf, "s4u2proxy fail", socket, cmd, True)
224 + r = run_cmd(testdir, env, conf, msg, socket, cmd, PROXY_KTNAME, True)
227 #Test s4u2proxy half succeed
229 socket = os.path.join(testdir, 'impersonate-proxyonly.socket')
230 cmd = ["./tests/t_impersonate", USR_NAME, HOST_GSS, PROXY_GSS,
231 path_prefix + 'impersonate.cache', 's4u2proxy']
232 - r = run_cmd(testdir, env, conf, "s4u2proxy", socket, cmd, False)
233 + r = run_cmd(testdir, env, conf, msg, socket, cmd, PROXY_KTNAME, False)
236 # Reset back gssproxy conf