Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/kdc/kdc_transit.c
34889 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* kdc/kdc_transit.c */
3
/*
4
* Copyright (C) 2012 by the Massachusetts Institute of Technology.
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
*
11
* * Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
13
*
14
* * Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in
16
* the documentation and/or other materials provided with the
17
* distribution.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30
* OF THE POSSIBILITY OF SUCH DAMAGE.
31
*/
32
33
#include "k5-int.h"
34
#include "kdc_util.h"
35
36
#define MAX_REALM_LN 500
37
38
/*
39
* subrealm - determine if r2 is a subrealm of r1
40
*
41
* SUBREALM takes two realms, r1 and r2, and
42
* determines if r2 is a subrealm of r1.
43
* r2 is a subrealm of r1 if (r1 is a prefix
44
* of r2 AND r1 and r2 begin with a /) or if
45
* (r1 is a suffix of r2 and neither r1 nor r2
46
* begin with a /).
47
*
48
* RETURNS: If r2 is a subrealm, and r1 is a prefix, the number
49
* of characters in the suffix of r2 is returned as a
50
* negative number.
51
*
52
* If r2 is a subrealm, and r1 is a suffix, the number
53
* of characters in the prefix of r2 is returned as a
54
* positive number.
55
*
56
* If r2 is not a subrealm, SUBREALM returns 0.
57
*/
58
static int
59
subrealm(char *r1, char *r2)
60
{
61
size_t l1,l2;
62
l1 = strlen(r1);
63
l2 = strlen(r2);
64
if(l2 <= l1) return(0);
65
if((*r1 == '/') && (*r2 == '/') && (strncmp(r1,r2,l1) == 0)) return(l1-l2);
66
if((*r1 != '/') && (*r2 != '/') && (strncmp(r1,r2+l2-l1,l1) == 0))
67
return(l2-l1);
68
return(0);
69
}
70
71
/*
72
* add_to_transited Adds the name of the realm which issued the
73
* ticket granting ticket on which the new ticket to
74
* be issued is based (note that this is the same as
75
* the realm of the server listed in the ticket
76
* granting ticket.
77
*
78
* ASSUMPTIONS: This procedure assumes that the transited field from
79
* the existing ticket granting ticket already appears
80
* in compressed form. It will add the new realm while
81
* maintaining that form. As long as each successive
82
* realm is added using this (or a similar) routine, the
83
* transited field will be in compressed form. The
84
* basis step is an empty transited field which is, by
85
* its nature, in its most compressed form.
86
*
87
* ARGUMENTS: krb5_data *tgt_trans Transited field from TGT
88
* krb5_data *new_trans The transited field for the new ticket
89
* krb5_principal tgs Name of ticket granting server
90
* This includes the realm of the KDC
91
* that issued the ticket granting
92
* ticket. This is the realm that is
93
* to be added to the transited field.
94
* krb5_principal client Name of the client
95
* krb5_principal server The name of the requested server.
96
* This may be the an intermediate
97
* ticket granting server.
98
*
99
* The last two argument are needed since they are
100
* implicitly part of the transited field of the new ticket
101
* even though they are not explicitly listed.
102
*
103
* RETURNS: krb5_error_code - Success, or out of memory
104
*
105
* MODIFIES: new_trans: ->length will contain the length of the new
106
* transited field.
107
*
108
* If ->data was not null when this procedure
109
* is called, the memory referenced by ->data
110
* will be deallocated.
111
*
112
* Memory will be allocated for the new transited field
113
* ->data will be updated to point to the newly
114
* allocated memory.
115
*
116
* BUGS: The space allocated for the new transited field is the
117
* maximum that might be needed given the old transited field,
118
* and the realm to be added. This length is calculated
119
* assuming that no compression of the new realm is possible.
120
* This has no adverse consequences other than the allocation
121
* of more space than required.
122
*
123
* This procedure will not yet use the null subfield notation,
124
* and it will get confused if it sees it.
125
*
126
* This procedure does not check for quoted commas in realm
127
* names.
128
*/
129
130
char *
131
data2string (krb5_data *d)
132
{
133
char *s;
134
s = malloc(d->length + 1);
135
if (s) {
136
if (d->length > 0)
137
memcpy(s, d->data, d->length);
138
s[d->length] = 0;
139
}
140
return s;
141
}
142
143
krb5_error_code
144
add_to_transited(krb5_data *tgt_trans, krb5_data *new_trans,
145
krb5_principal tgs, krb5_principal client,
146
krb5_principal server)
147
{
148
krb5_error_code retval;
149
char *realm;
150
char *trans;
151
char *otrans, *otrans_ptr;
152
size_t bufsize;
153
154
/* The following are for stepping through the transited field */
155
156
char prev[MAX_REALM_LN];
157
char next[MAX_REALM_LN];
158
char current[MAX_REALM_LN];
159
char exp[MAX_REALM_LN]; /* Expanded current realm name */
160
161
int i;
162
int clst, nlst; /* count of last character in current and next */
163
int pl, pl1; /* prefix length */
164
int added; /* TRUE = new realm has been added */
165
166
realm = data2string(krb5_princ_realm(kdc_context, tgs));
167
if (realm == NULL)
168
return(ENOMEM);
169
170
otrans = data2string(tgt_trans);
171
if (otrans == NULL) {
172
free(realm);
173
return(ENOMEM);
174
}
175
/* Keep track of start so we can free */
176
otrans_ptr = otrans;
177
178
/* +1 for null,
179
+1 for extra comma which may be added between
180
+1 for potential space when leading slash in realm */
181
bufsize = strlen(realm) + strlen(otrans) + 3;
182
if (bufsize > MAX_REALM_LN)
183
bufsize = MAX_REALM_LN;
184
if (!(trans = (char *) malloc(bufsize))) {
185
retval = ENOMEM;
186
goto fail;
187
}
188
189
if (new_trans->data) free(new_trans->data);
190
new_trans->data = trans;
191
new_trans->length = 0;
192
193
trans[0] = '\0';
194
195
/* For the purpose of appending, the realm preceding the first */
196
/* realm in the transited field is considered the null realm */
197
198
prev[0] = '\0';
199
200
/* read field into current */
201
for (i = 0; *otrans != '\0';) {
202
if (*otrans == '\\') {
203
if (*(++otrans) == '\0')
204
break;
205
else
206
continue;
207
}
208
if (*otrans == ',') {
209
otrans++;
210
break;
211
}
212
current[i++] = *otrans++;
213
if (i >= MAX_REALM_LN) {
214
retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
215
goto fail;
216
}
217
}
218
current[i] = '\0';
219
220
added = (krb5_princ_realm(kdc_context, client)->length == strlen(realm) &&
221
!strncmp(krb5_princ_realm(kdc_context, client)->data, realm, strlen(realm))) ||
222
(krb5_princ_realm(kdc_context, server)->length == strlen(realm) &&
223
!strncmp(krb5_princ_realm(kdc_context, server)->data, realm, strlen(realm)));
224
225
while (current[0]) {
226
227
/* figure out expanded form of current name */
228
229
clst = strlen(current) - 1;
230
if (current[0] == ' ') {
231
strncpy(exp, current+1, sizeof(exp) - 1);
232
exp[sizeof(exp) - 1] = '\0';
233
}
234
else if ((current[0] == '/') && (prev[0] == '/')) {
235
strncpy(exp, prev, sizeof(exp) - 1);
236
exp[sizeof(exp) - 1] = '\0';
237
if (strlen(exp) + strlen(current) + 1 >= MAX_REALM_LN) {
238
retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
239
goto fail;
240
}
241
strncat(exp, current, sizeof(exp) - 1 - strlen(exp));
242
}
243
else if (current[clst] == '.') {
244
strncpy(exp, current, sizeof(exp) - 1);
245
exp[sizeof(exp) - 1] = '\0';
246
if (strlen(exp) + strlen(prev) + 1 >= MAX_REALM_LN) {
247
retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
248
goto fail;
249
}
250
strncat(exp, prev, sizeof(exp) - 1 - strlen(exp));
251
}
252
else {
253
strncpy(exp, current, sizeof(exp) - 1);
254
exp[sizeof(exp) - 1] = '\0';
255
}
256
257
/* read field into next */
258
for (i = 0; *otrans != '\0';) {
259
if (*otrans == '\\') {
260
if (*(++otrans) == '\0')
261
break;
262
else
263
continue;
264
}
265
if (*otrans == ',') {
266
otrans++;
267
break;
268
}
269
next[i++] = *otrans++;
270
if (i >= MAX_REALM_LN) {
271
retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
272
goto fail;
273
}
274
}
275
next[i] = '\0';
276
nlst = i - 1;
277
278
if (!strcmp(exp, realm)) added = TRUE;
279
280
/* If we still have to insert the new realm */
281
282
if (!added) {
283
284
/* Is the next field compressed? If not, and if the new */
285
/* realm is a subrealm of the current realm, compress */
286
/* the new realm, and insert immediately following the */
287
/* current one. Note that we can not do this if the next*/
288
/* field is already compressed since it would mess up */
289
/* what has already been done. In most cases, this is */
290
/* not a problem because the realm to be added will be a */
291
/* subrealm of the next field too, and we will catch */
292
/* it in a future iteration. */
293
294
/* Note that the second test here is an unsigned comparison,
295
so the first half (or a cast) is also required. */
296
assert(nlst < 0 || nlst < (int)sizeof(next));
297
if ((nlst < 0 || next[nlst] != '.') &&
298
(next[0] != '/') &&
299
(pl = subrealm(exp, realm))) {
300
added = TRUE;
301
current[sizeof(current) - 1] = '\0';
302
if (strlen(current) + (pl>0?pl:-pl) + 2 >= MAX_REALM_LN) {
303
retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
304
goto fail;
305
}
306
strncat(current, ",", sizeof(current) - 1 - strlen(current));
307
if (pl > 0) {
308
strncat(current, realm, (unsigned) pl);
309
}
310
else {
311
strncat(current, realm+strlen(realm)+pl, (unsigned) (-pl));
312
}
313
}
314
315
/* Whether or not the next field is compressed, if the */
316
/* realm to be added is a superrealm of the current realm,*/
317
/* then the current realm can be compressed. First the */
318
/* realm to be added must be compressed relative to the */
319
/* previous realm (if possible), and then the current */
320
/* realm compressed relative to the new realm. Note that */
321
/* if the realm to be added is also a superrealm of the */
322
/* previous realm, it would have been added earlier, and */
323
/* we would not reach this step this time around. */
324
325
else if ((pl = subrealm(realm, exp))) {
326
added = TRUE;
327
current[0] = '\0';
328
if ((pl1 = subrealm(prev,realm))) {
329
if (strlen(current) + (pl1>0?pl1:-pl1) + 1 >= MAX_REALM_LN) {
330
retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
331
goto fail;
332
}
333
if (pl1 > 0) {
334
strncat(current, realm, (unsigned) pl1);
335
}
336
else {
337
strncat(current, realm+strlen(realm)+pl1, (unsigned) (-pl1));
338
}
339
}
340
else { /* If not a subrealm */
341
if ((realm[0] == '/') && prev[0]) {
342
if (strlen(current) + 2 >= MAX_REALM_LN) {
343
retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
344
goto fail;
345
}
346
strncat(current, " ", sizeof(current) - 1 - strlen(current));
347
current[sizeof(current) - 1] = '\0';
348
}
349
if (strlen(current) + strlen(realm) + 1 >= MAX_REALM_LN) {
350
retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
351
goto fail;
352
}
353
strncat(current, realm, sizeof(current) - 1 - strlen(current));
354
current[sizeof(current) - 1] = '\0';
355
}
356
if (strlen(current) + (pl>0?pl:-pl) + 2 >= MAX_REALM_LN) {
357
retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
358
goto fail;
359
}
360
strncat(current,",", sizeof(current) - 1 - strlen(current));
361
current[sizeof(current) - 1] = '\0';
362
if (pl > 0) {
363
strncat(current, exp, (unsigned) pl);
364
}
365
else {
366
strncat(current, exp+strlen(exp)+pl, (unsigned)(-pl));
367
}
368
}
369
}
370
371
if (new_trans->length != 0) {
372
if (strlcat(trans, ",", bufsize) >= bufsize) {
373
retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
374
goto fail;
375
}
376
}
377
if (strlcat(trans, current, bufsize) >= bufsize) {
378
retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
379
goto fail;
380
}
381
new_trans->length = strlen(trans);
382
383
strncpy(prev, exp, sizeof(prev) - 1);
384
prev[sizeof(prev) - 1] = '\0';
385
strncpy(current, next, sizeof(current) - 1);
386
current[sizeof(current) - 1] = '\0';
387
}
388
389
if (!added) {
390
if (new_trans->length != 0) {
391
if (strlcat(trans, ",", bufsize) >= bufsize) {
392
retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
393
goto fail;
394
}
395
}
396
if((realm[0] == '/') && trans[0]) {
397
if (strlcat(trans, " ", bufsize) >= bufsize) {
398
retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
399
goto fail;
400
}
401
}
402
if (strlcat(trans, realm, bufsize) >= bufsize) {
403
retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
404
goto fail;
405
}
406
new_trans->length = strlen(trans);
407
}
408
409
retval = 0;
410
fail:
411
free(realm);
412
free(otrans_ptr);
413
return (retval);
414
}
415
416