summaryrefslogtreecommitdiffstats
path: root/krb5-trunk-7046.patch
blob: 7db7ef5f3b4fd15b698fb6fca878a92d83d73c6e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
commit 9dc75551cb8cc4c03f7e0fe5e8a705ed678079f4
Author: ghudson <ghudson@dc483132-0cff-0310-8789-dd5450dbe970>
Date:   Wed Dec 7 19:38:13 2011 +0000

    ticket: 7046
    subject: Allow S4U2Proxy delegated credentials to be saved
    
    The initial implementation of client-side S4U2Proxy support did not
    allow delegated proxy credentials to be stored (gss_store_cred would
    error out, and gss_krb5_copy_ccache would generate a non-working
    cache).  To make this work, we save the impersonator name in a cache
    config variable and in a cred structure field (replacing the
    proxy_cred flag), and make the default principal of the proxy cache
    the subject principal as the caller would expect for a regular
    delegated cred.
    
    git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25529 dc483132-0cff-0310-8789-dd5450dbe970

diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index 514e2ea..b25c159 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -273,7 +273,10 @@ typedef INT64_TYPE krb5_int64;
 #define KRB5_CONF_V4_INSTANCE_CONVERT         "v4_instance_convert"
 #define KRB5_CONF_V4_REALM                    "v4_realm"
 #define KRB5_CONF_ASTERISK                    "*"
+
+/* Cache configuration variables */
 #define KRB5_CONF_FAST_AVAIL                  "fast_avail"
+#define KRB5_CONF_PROXY_IMPERSONATOR          "proxy_impersonator"
 
 /* Error codes used in KRB_ERROR protocol messages.
    Return values of library routines are based on a different error table
diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c
index c815b35..c08e059 100644
--- a/src/lib/gssapi/krb5/acquire_cred.c
+++ b/src/lib/gssapi/krb5/acquire_cred.c
@@ -417,6 +417,34 @@ prep_ccache(krb5_context context, krb5_gss_cred_id_rec *cred,
     return 0;
 }
 
+/* If an impersonator config entry exists in ccache, set *impersonator_out to
+ * the parsed principal.  Otherwise set *impersonator_out to NULL. */
+static krb5_error_code
+get_impersonator(krb5_context context, krb5_ccache ccache,
+                 krb5_principal *impersonator_out)
+{
+    krb5_error_code code;
+    krb5_data data = empty_data(), data0 = empty_data();
+
+    *impersonator_out = NULL;
+
+    code = krb5_cc_get_config(context, ccache, NULL,
+                              KRB5_CONF_PROXY_IMPERSONATOR, &data);
+    if (code)
+        return (code == KRB5_CC_NOTFOUND) ? 0 : code;
+
+    code = krb5int_copy_data_contents_add0(context, &data, &data0);
+    if (code)
+        goto cleanup;
+
+    code = krb5_parse_name(context, data0.data, impersonator_out);
+
+cleanup:
+    krb5_free_data_contents(context, &data);
+    krb5_free_data_contents(context, &data0);
+    return code;
+}
+
 /* Check ccache and scan it for its expiry time.  On success, cred takes
  * ownership of ccache. */
 static krb5_error_code
@@ -493,6 +521,10 @@ scan_ccache(krb5_context context, krb5_gss_cred_id_rec *cred,
         goto cleanup;
     }
 
+    code = get_impersonator(context, ccache, &cred->impersonator);
+    if (code)
+        goto cleanup;
+
     (void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
     cred->ccache = ccache;
 
@@ -622,6 +654,7 @@ acquire_cred(OM_uint32 *minor_status,
 
     cred->usage = args->cred_usage;
     cred->name = NULL;
+    cred->impersonator = NULL;
     cred->iakerb_mech = args->iakerb;
     cred->default_identity = (name == NULL);
 #ifndef LEAN_CLIENT
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
index 016a2e6..6b7d530 100644
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -172,7 +172,7 @@ typedef struct _krb5_gss_cred_id_rec {
     /* name/type of credential */
     gss_cred_usage_t usage;
     krb5_gss_name_t name;
-    unsigned int proxy_cred : 1;
+    krb5_principal impersonator;
     unsigned int default_identity : 1;
     unsigned int iakerb_mech : 1;
     unsigned int destroy_ccache : 1;
diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c
index 1b8120c..d7b9ffa 100644
--- a/src/lib/gssapi/krb5/init_sec_context.c
+++ b/src/lib/gssapi/krb5/init_sec_context.c
@@ -129,7 +129,6 @@ static krb5_error_code get_credentials(context, cred, server, now,
     krb5_error_code     code;
     krb5_creds          in_creds, evidence_creds, *result_creds = NULL;
     krb5_flags          flags = 0;
-    krb5_principal      cc_princ = NULL;
 
     *out_creds = NULL;
 
@@ -140,16 +139,13 @@ static krb5_error_code get_credentials(context, cred, server, now,
 
     assert(cred->name != NULL);
 
-    if ((code = krb5_cc_get_principal(context, cred->ccache, &cc_princ)))
-        goto cleanup;
-
     /*
      * Do constrained delegation if we have proxy credentials and
      * we're not trying to get a ticket to ourselves (in which case
      * we can just use the S4U2Self or evidence ticket directly).
      */
-    if (cred->proxy_cred &&
-        !krb5_principal_compare(context, cc_princ, server->princ)) {
+    if (cred->impersonator &&
+        !krb5_principal_compare(context, cred->impersonator, server->princ)) {
         krb5_creds mcreds;
 
         flags |= KRB5_GC_CANONICALIZE |
@@ -159,20 +155,18 @@ static krb5_error_code get_credentials(context, cred, server, now,
         memset(&mcreds, 0, sizeof(mcreds));
 
         mcreds.magic = KV5M_CREDS;
-        mcreds.times.endtime = cred->tgt_expire;
-        mcreds.server = cc_princ;
+        mcreds.server = cred->impersonator;
         mcreds.client = cred->name->princ;
 
         code = krb5_cc_retrieve_cred(context, cred->ccache,
-                                     KRB5_TC_MATCH_TIMES | KRB5_TC_MATCH_AUTHDATA,
-                                     &mcreds,
+                                     KRB5_TC_MATCH_AUTHDATA, &mcreds,
                                      &evidence_creds);
         if (code)
             goto cleanup;
 
         assert(evidence_creds.ticket_flags & TKT_FLG_FORWARDABLE);
 
-        in_creds.client = cc_princ;
+        in_creds.client = cred->impersonator;
         in_creds.second_ticket = evidence_creds.ticket;
     } else {
         in_creds.client = cred->name->princ;
@@ -255,7 +249,6 @@ static krb5_error_code get_credentials(context, cred, server, now,
 
 cleanup:
     krb5_free_authdata(context, in_creds.authdata);
-    krb5_free_principal(context, cc_princ);
     krb5_free_cred_contents(context, &evidence_creds);
     krb5_free_creds(context, result_creds);
 
diff --git a/src/lib/gssapi/krb5/rel_cred.c b/src/lib/gssapi/krb5/rel_cred.c
index 5b2ea2f..4fd3694 100644
--- a/src/lib/gssapi/krb5/rel_cred.c
+++ b/src/lib/gssapi/krb5/rel_cred.c
@@ -71,6 +71,8 @@ krb5_gss_release_cred(minor_status, cred_handle)
     if (cred->name)
         kg_release_name(context, &cred->name);
 
+    krb5_free_principal(context, cred->impersonator);
+
     if (cred->req_enctypes)
         free(cred->req_enctypes);
 
diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c
index 4ac2ce3..4b37c5a 100644
--- a/src/lib/gssapi/krb5/s4u_gss_glue.c
+++ b/src/lib/gssapi/krb5/s4u_gss_glue.c
@@ -169,6 +169,39 @@ krb5_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
 
 }
 
+/*
+ * Set up cred to be an S4U2Proxy credential by copying in the impersonator's
+ * creds, setting a cache config variable with the impersonator principal name,
+ * and saving the impersonator principal name in the cred structure.
+ */
+static krb5_error_code
+make_proxy_cred(krb5_context context, krb5_gss_cred_id_t cred,
+                krb5_gss_cred_id_t impersonator_cred)
+{
+    krb5_error_code code;
+    krb5_data data;
+    char *str;
+
+    code = krb5_cc_copy_creds(context, impersonator_cred->ccache,
+                              cred->ccache);
+    if (code)
+        return code;
+
+    code = krb5_unparse_name(context, impersonator_cred->name->princ, &str);
+    if (code)
+        return code;
+
+    data = string2data(str);
+    code = krb5_cc_set_config(context, cred->ccache, NULL,
+                              KRB5_CONF_PROXY_IMPERSONATOR, &data);
+    krb5_free_unparsed_name(context, str);
+    if (code)
+        return code;
+
+    return krb5_copy_principal(context, impersonator_cred->name->princ,
+                               &cred->impersonator);
+}
+
 OM_uint32
 kg_compose_deleg_cred(OM_uint32 *minor_status,
                       krb5_gss_cred_id_t impersonator_cred,
@@ -187,7 +220,7 @@ kg_compose_deleg_cred(OM_uint32 *minor_status,
 
     if (!kg_is_initiator_cred(impersonator_cred) ||
         impersonator_cred->name == NULL ||
-        impersonator_cred->proxy_cred) {
+        impersonator_cred->impersonator != NULL) {
         code = G_BAD_USAGE;
         goto cleanup;
     }
@@ -208,14 +241,7 @@ kg_compose_deleg_cred(OM_uint32 *minor_status,
     if (code != 0)
         goto cleanup;
 
-    /*
-     * Only return a "proxy" credential for use with constrained
-     * delegation if the subject credentials are forwardable.
-     * Submitting non-forwardable credentials to the KDC for use
-     * with constrained delegation will only return an error.
-     */
     cred->usage = GSS_C_INITIATE;
-    cred->proxy_cred = !!(subject_creds->ticket_flags & TKT_FLG_FORWARDABLE);
 
     cred->tgt_expire = subject_creds->times.endtime;
 
@@ -229,16 +255,18 @@ kg_compose_deleg_cred(OM_uint32 *minor_status,
         goto cleanup;
     cred->destroy_ccache = 1;
 
-    code = krb5_cc_initialize(context, cred->ccache,
-                              cred->proxy_cred ? impersonator_cred->name->princ :
-                              subject_creds->client);
+    code = krb5_cc_initialize(context, cred->ccache, subject_creds->client);
     if (code != 0)
         goto cleanup;
 
-    if (cred->proxy_cred) {
-        /* Impersonator's TGT will be necessary for S4U2Proxy */
-        code = krb5_cc_copy_creds(context, impersonator_cred->ccache,
-                                  cred->ccache);
+    /*
+     * Only return a "proxy" credential for use with constrained
+     * delegation if the subject credentials are forwardable.
+     * Submitting non-forwardable credentials to the KDC for use
+     * with constrained delegation will only return an error.
+     */
+    if (subject_creds->ticket_flags & TKT_FLG_FORWARDABLE) {
+        code = make_proxy_cred(context, cred, impersonator_cred);
         if (code != 0)
             goto cleanup;
     }
diff --git a/src/lib/gssapi/krb5/store_cred.c b/src/lib/gssapi/krb5/store_cred.c
index bff3cde..d587589 100644
--- a/src/lib/gssapi/krb5/store_cred.c
+++ b/src/lib/gssapi/krb5/store_cred.c
@@ -91,7 +91,7 @@ copy_initiator_creds(OM_uint32 *minor_status,
 
     kcred = (krb5_gss_cred_id_t)input_cred_handle;
 
-    if (kcred->ccache == NULL || kcred->proxy_cred) {
+    if (kcred->ccache == NULL) {
         *minor_status = KG_CCACHE_NOMATCH;
         major_status = GSS_S_DEFECTIVE_CREDENTIAL;
         goto cleanup;
diff --git a/src/lib/gssapi/krb5/val_cred.c b/src/lib/gssapi/krb5/val_cred.c
index e87f249..46a9ae1 100644
--- a/src/lib/gssapi/krb5/val_cred.c
+++ b/src/lib/gssapi/krb5/val_cred.c
@@ -50,8 +50,7 @@ krb5_gss_validate_cred_1(OM_uint32 *minor_status, gss_cred_id_t cred_handle,
             *minor_status = code;
             return(GSS_S_DEFECTIVE_CREDENTIAL);
         }
-        if (!cred->proxy_cred &&
-            !krb5_principal_compare(context, princ, cred->name->princ)) {
+        if (!krb5_principal_compare(context, princ, cred->name->princ)) {
             k5_mutex_unlock(&cred->lock);
             *minor_status = KG_CCACHE_NOMATCH;
             return(GSS_S_DEFECTIVE_CREDENTIAL);