~ubuntu-branches/ubuntu/maverick/krb5/maverick

« back to all changes in this revision

Viewing changes to src/kdc/do_tgs_req.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hartman
  • Date: 2009-05-07 16:16:34 UTC
  • mfrom: (13.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20090507161634-xqyk0s9na0le4flj
Tags: 1.7dfsg~beta1-4
When  decrypting the TGS response fails with the subkey, try with the
session key to work around Heimdal bug, Closes: #527353 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * kdc/do_tgs_req.c
3
3
 *
4
 
 * Copyright 1990,1991,2001 by the Massachusetts Institute of Technology.
 
4
 * Copyright 1990,1991,2001,2007,2008,2009 by the Massachusetts Institute of Technology.
5
5
 * All Rights Reserved.
6
6
 *
7
7
 * Export of this software from the United States of America may
26
26
 *
27
27
 * KDC Routines to deal with TGS_REQ's
28
28
 */
 
29
/*
 
30
 * Copyright (c) 2006-2008, Novell, Inc.
 
31
 * All rights reserved.
 
32
 *
 
33
 * Redistribution and use in source and binary forms, with or without
 
34
 * modification, are permitted provided that the following conditions are met:
 
35
 *
 
36
 *   * Redistributions of source code must retain the above copyright notice,
 
37
 *       this list of conditions and the following disclaimer.
 
38
 *   * Redistributions in binary form must reproduce the above copyright
 
39
 *       notice, this list of conditions and the following disclaimer in the
 
40
 *       documentation and/or other materials provided with the distribution.
 
41
 *   * The copyright holder's name is not used to endorse or promote products
 
42
 *       derived from this software without specific prior written permission.
 
43
 *
 
44
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 
45
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
46
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
47
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 
48
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
49
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
50
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
51
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
52
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
53
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
54
 * POSSIBILITY OF SUCH DAMAGE.
 
55
 */
29
56
 
30
57
#include "k5-int.h"
31
 
#include "com_err.h"
32
58
 
33
59
#include <syslog.h>
34
60
#ifdef HAVE_NETINET_IN_H
43
69
#include "policy.h"
44
70
#include "extern.h"
45
71
#include "adm_proto.h"
46
 
 
47
 
 
48
 
static void find_alternate_tgs (krb5_kdc_req *, krb5_db_entry *,
49
 
                                krb5_boolean *, int *);
50
 
 
51
 
static krb5_error_code prepare_error_tgs (krb5_kdc_req *, krb5_ticket *,
52
 
                                          int, const char *, krb5_data **,
53
 
                                          const char *);
 
72
#include <ctype.h>
 
73
 
 
74
static void 
 
75
find_alternate_tgs(krb5_kdc_req *,krb5_db_entry *,
 
76
                   krb5_boolean *,int *);
 
77
 
 
78
static krb5_error_code 
 
79
prepare_error_tgs(struct kdc_request_state *, krb5_kdc_req *,krb5_ticket *,int,
 
80
                  krb5_principal,krb5_data **,const char *);
 
81
 
 
82
static krb5_int32
 
83
prep_reprocess_req(krb5_kdc_req *,krb5_principal *);
54
84
 
55
85
/*ARGSUSED*/
56
86
krb5_error_code
57
87
process_tgs_req(krb5_data *pkt, const krb5_fulladdr *from,
58
 
                krb5_data **response)
 
88
                krb5_data **response)
59
89
{
60
 
    krb5_keyblock * subkey;
 
90
    krb5_keyblock * subkey = 0;
61
91
    krb5_kdc_req *request = 0;
62
92
    krb5_db_entry server;
63
93
    krb5_kdc_rep reply;
68
98
    krb5_transited enc_tkt_transited;
69
99
    int newtransited = 0;
70
100
    krb5_error_code retval = 0;
 
101
    krb5_keyblock encrypting_key;
71
102
    int nprincs = 0;
72
103
    krb5_boolean more;
73
104
    krb5_timestamp kdc_time, authtime=0;
74
105
    krb5_keyblock session_key;
75
106
    krb5_timestamp until, rtime;
76
 
    krb5_keyblock encrypting_key;
 
107
    krb5_keyblock *reply_key = NULL;
 
108
    krb5_keyblock *mkey_ptr;
77
109
    krb5_key_data  *server_key;
78
 
    char *cname = 0, *sname = 0, *tmp = 0;
79
 
    const char *fromstring = 0;
 
110
    char *cname = 0, *sname = 0, *altcname = 0;
80
111
    krb5_last_req_entry *nolrarray[2], nolrentry;
81
 
/*    krb5_address *noaddrarray[1]; */
82
112
    krb5_enctype useenctype;
83
 
    int errcode, errcode2;
 
113
    int errcode, errcode2;
84
114
    register int i;
85
115
    int firstpass = 1;
86
 
    const char  *status = 0;
87
 
    char ktypestr[128];
88
 
    char rep_etypestr[128];
89
 
    char fromstringbuf[70];
 
116
    const char        *status = 0;
 
117
    krb5_enc_tkt_part *header_enc_tkt = NULL; /* ticket granting or evidence ticket */
 
118
    krb5_db_entry client, krbtgt;
 
119
    int c_nprincs = 0, k_nprincs = 0;
 
120
    krb5_pa_for_user *for_user = NULL;           /* protocol transition request */
 
121
    krb5_authdata **kdc_issued_auth_data = NULL; /* auth data issued by KDC */
 
122
    unsigned int c_flags = 0, s_flags = 0;       /* client/server KDB flags */
 
123
    char *s4u_name = NULL;
 
124
    krb5_boolean is_referral, db_ref_done = FALSE;
 
125
    const char *emsg = NULL;
 
126
    krb5_data *tgs_1 =NULL, *server_1 = NULL;
 
127
    krb5_principal krbtgt_princ;
 
128
    krb5_kvno ticket_kvno = 0;
 
129
    struct kdc_request_state *state = NULL;
 
130
    krb5_pa_data *pa_tgs_req; /*points into request*/
 
131
    krb5_data scratch;
90
132
 
91
 
    session_key.contents = 0;
 
133
    session_key.contents = NULL;
92
134
    
93
135
    retval = decode_krb5_tgs_req(pkt, &request);
94
136
    if (retval)
95
 
        return retval;
 
137
        return retval;
96
138
 
97
 
    ktypes2str(ktypestr, sizeof(ktypestr),
98
 
               request->nktypes, request->ktype);
99
139
    /*
100
140
     * setup_server_realm() sets up the global realm-specific data pointer.
101
141
     */
102
 
    if ((retval = setup_server_realm(request->server)))
103
 
        return retval;
104
 
 
105
 
    fromstring = inet_ntop(ADDRTYPE2FAMILY(from->address->addrtype),
106
 
                           from->address->contents,
107
 
                           fromstringbuf, sizeof(fromstringbuf));
108
 
    if (!fromstring)
109
 
        fromstring = "<unknown>";
110
 
 
111
 
    if ((errcode = krb5_unparse_name(kdc_context, request->server, &sname))) {
112
 
        status = "UNPARSING SERVER";
113
 
        goto cleanup;
 
142
    if ((retval = setup_server_realm(request->server))) {
 
143
        krb5_free_kdc_req(kdc_context, request);
 
144
        return retval;
114
145
    }
115
 
    limit_string(sname);
116
 
 
117
 
   /* errcode = kdc_process_tgs_req(request, from, pkt, &req_authdat); */
118
 
    errcode = kdc_process_tgs_req(request, from, pkt, &header_ticket, &subkey);
119
 
 
 
146
    errcode = kdc_process_tgs_req(request, from, pkt, &header_ticket,
 
147
                                  &krbtgt, &k_nprincs, &subkey, &pa_tgs_req);
120
148
    if (header_ticket && header_ticket->enc_part2 &&
121
 
        (errcode2 = krb5_unparse_name(kdc_context, 
122
 
                                      header_ticket->enc_part2->client,
123
 
                                      &cname))) {
124
 
        status = "UNPARSING CLIENT";
125
 
        errcode = errcode2;
126
 
        goto cleanup;
 
149
        (errcode2 = krb5_unparse_name(kdc_context, 
 
150
                                      header_ticket->enc_part2->client,
 
151
                                      &cname))) {
 
152
        status = "UNPARSING CLIENT";
 
153
        errcode = errcode2;
 
154
        goto cleanup;
127
155
    }
128
156
    limit_string(cname);
129
157
    
130
158
    if (errcode) {
131
 
        status = "PROCESS_TGS";
132
 
        goto cleanup;
 
159
        status = "PROCESS_TGS";
 
160
        goto cleanup;
133
161
    }
134
162
 
135
163
    if (!header_ticket) {
136
 
        errcode = KRB5_NO_TKT_SUPPLIED; /* XXX? */
137
 
        status="UNEXPECTED NULL in header_ticket";
 
164
        errcode = KRB5_NO_TKT_SUPPLIED;        /* XXX? */
 
165
        status="UNEXPECTED NULL in header_ticket";
 
166
        goto cleanup;
 
167
    }
 
168
    errcode = kdc_make_rstate(&state);
 
169
    if (errcode !=0) {
 
170
        status = "making state";
138
171
        goto cleanup;
139
172
    }
 
173
    scratch.length = pa_tgs_req->length;
 
174
    scratch.data = (char *) pa_tgs_req->contents;
 
175
    errcode = kdc_find_fast(&request, &scratch, subkey, header_ticket->enc_part2->session, state);
 
176
    if (errcode !=0) {
 
177
        status = "kdc_find_fast";
 
178
                goto cleanup;
 
179
    }
 
180
    
 
181
    
 
182
    /*
 
183
     * Pointer to the encrypted part of the header ticket, which may be
 
184
     * replaced to point to the encrypted part of the evidence ticket
 
185
     * if constrained delegation is used. This simplifies the number of
 
186
     * special cases for constrained delegation.
 
187
     */
 
188
    header_enc_tkt = header_ticket->enc_part2;
140
189
    
141
190
    /*
142
191
     * We've already dealt with the AP_REQ authentication, so we can
144
193
     * decrypted with the session key.
145
194
     */
146
195
 
147
 
    authtime = header_ticket->enc_part2->times.authtime;
148
 
 
149
196
    /* XXX make sure server here has the proper realm...taken from AP_REQ
150
197
       header? */
151
198
 
 
199
    if (isflagset(request->kdc_options, KDC_OPT_CANONICALIZE)) {
 
200
        setflag(c_flags, KRB5_KDB_FLAG_CANONICALIZE);
 
201
        setflag(s_flags, KRB5_KDB_FLAG_CANONICALIZE);
 
202
    }
 
203
 
 
204
    db_ref_done = FALSE;
 
205
ref_tgt_again:
152
206
    nprincs = 1;
153
 
    if ((errcode = krb5_db_get_principal(kdc_context, request->server, &server,
154
 
                                        &nprincs, &more))) {
155
 
        status = "LOOKING_UP_SERVER";
156
 
        nprincs = 0;
157
 
        goto cleanup;
 
207
    if ((errcode = krb5_unparse_name(kdc_context, request->server, &sname))) {
 
208
        status = "UNPARSING SERVER";
 
209
        goto cleanup;
 
210
    }
 
211
    limit_string(sname);
 
212
 
 
213
    errcode = krb5_db_get_principal_ext(kdc_context,
 
214
                                        request->server,
 
215
                                        s_flags,
 
216
                                        &server,
 
217
                                        &nprincs,
 
218
                                        &more);
 
219
    if (errcode) {
 
220
        status = "LOOKING_UP_SERVER";
 
221
        nprincs = 0;
 
222
        goto cleanup;
158
223
    }
159
224
tgt_again:
160
225
    if (more) {
161
 
        status = "NON_UNIQUE_PRINCIPAL";
162
 
        errcode = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
163
 
        goto cleanup;
 
226
        status = "NON_UNIQUE_PRINCIPAL";
 
227
        errcode = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
 
228
        goto cleanup;
164
229
    } else if (nprincs != 1) {
165
 
        /*
166
 
         * might be a request for a TGT for some other realm; we
167
 
         * should do our best to find such a TGS in this db
168
 
         */
169
 
        if (firstpass && krb5_is_tgs_principal(request->server) == TRUE) {
170
 
            if (krb5_princ_size(kdc_context, request->server) == 2) {
171
 
                krb5_data *server_1 =
172
 
                    krb5_princ_component(kdc_context, request->server, 1);
173
 
                krb5_data *tgs_1 =
174
 
                    krb5_princ_component(kdc_context, tgs_server, 1);
175
 
 
176
 
                if (!tgs_1 || server_1->length != tgs_1->length ||
177
 
                    memcmp(server_1->data, tgs_1->data, tgs_1->length)) {
178
 
                    krb5_db_free_principal(kdc_context, &server, nprincs);
179
 
                    find_alternate_tgs(request, &server, &more, &nprincs);
180
 
                    firstpass = 0;
181
 
                    goto tgt_again;
182
 
                }
183
 
            }
184
 
        }
185
 
        krb5_db_free_principal(kdc_context, &server, nprincs);
186
 
        status = "UNKNOWN_SERVER";
187
 
        errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
188
 
        goto cleanup;
 
230
        /*
 
231
         * might be a request for a TGT for some other realm; we
 
232
         * should do our best to find such a TGS in this db
 
233
         */
 
234
        if (firstpass ) {
 
235
 
 
236
            if ( krb5_is_tgs_principal(request->server) == TRUE) { /* Principal is a name of krb ticket service */
 
237
                if (krb5_princ_size(kdc_context, request->server) == 2) { 
 
238
                                          
 
239
                    server_1 = krb5_princ_component(kdc_context, request->server, 1);
 
240
                    tgs_1 = krb5_princ_component(kdc_context, tgs_server, 1);
 
241
 
 
242
                    if (!tgs_1 || !data_eq(*server_1, *tgs_1)) {
 
243
                        krb5_db_free_principal(kdc_context, &server, nprincs);
 
244
                        find_alternate_tgs(request, &server, &more, &nprincs);
 
245
                        firstpass = 0;
 
246
                        goto tgt_again;
 
247
                    }
 
248
                }  
 
249
                krb5_db_free_principal(kdc_context, &server, nprincs);
 
250
                status = "UNKNOWN_SERVER";
 
251
                errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
 
252
                goto cleanup;
 
253
 
 
254
            } else if ( db_ref_done == FALSE) {
 
255
                retval = prep_reprocess_req(request, &krbtgt_princ);
 
256
                if (!retval) {
 
257
                    krb5_free_principal(kdc_context, request->server);
 
258
                    retval = krb5_copy_principal(kdc_context, krbtgt_princ, &(request->server));
 
259
                    if (!retval) {
 
260
                        db_ref_done = TRUE;
 
261
                        if (sname != NULL) 
 
262
                            free(sname);
 
263
                        goto ref_tgt_again;
 
264
                    }
 
265
                }
 
266
            }
 
267
        }
 
268
 
 
269
        krb5_db_free_principal(kdc_context, &server, nprincs);
 
270
        status = "UNKNOWN_SERVER";
 
271
        errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
 
272
        goto cleanup;
189
273
    }
190
274
 
191
275
    if ((errcode = krb5_timeofday(kdc_context, &kdc_time))) {
192
 
        status = "TIME_OF_DAY";
193
 
        goto cleanup;
 
276
        status = "TIME_OF_DAY";
 
277
        goto cleanup;
194
278
    }
195
279
    
196
280
    if ((retval = validate_tgs_request(request, server, header_ticket,
197
 
                                      kdc_time, &status))) {
198
 
        if (!status)
199
 
            status = "UNKNOWN_REASON";
200
 
        errcode = retval + ERROR_TABLE_BASE_krb5;
201
 
        goto cleanup;
 
281
                                       kdc_time, &status))) {
 
282
    if (!status)
 
283
        status = "UNKNOWN_REASON";
 
284
        errcode = retval + ERROR_TABLE_BASE_krb5;
 
285
        goto cleanup;
202
286
    }
203
287
 
 
288
    if (!is_local_principal(header_enc_tkt->client))
 
289
        setflag(c_flags, KRB5_KDB_FLAG_CROSS_REALM);
 
290
 
 
291
    is_referral = krb5_is_tgs_principal(server.princ) &&
 
292
        !krb5_principal_compare(kdc_context, tgs_server, server.princ);
 
293
 
 
294
    /* Check for protocol transition */
 
295
    errcode = kdc_process_s4u2self_req(kdc_context, request, header_enc_tkt->client,
 
296
                                       &server, header_enc_tkt->session, kdc_time,
 
297
                                       &for_user, &client, &c_nprincs, &status);
 
298
    if (errcode)
 
299
        goto cleanup;
 
300
    if (for_user != NULL)
 
301
        setflag(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION);
 
302
 
204
303
    /*
205
304
     * We pick the session keytype here....
206
305
     * 
213
312
     * to anything else.
214
313
     */
215
314
    useenctype = 0;
216
 
    if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) {
217
 
        krb5_keyblock * st_sealing_key;
218
 
        krb5_kvno       st_srv_kvno;
219
 
        krb5_enctype    etype;
220
 
 
221
 
        /*
222
 
         * Get the key for the second ticket, and decrypt it.
223
 
         */
224
 
        if ((errcode = kdc_get_server_key(request->second_ticket[st_idx],
225
 
                                         &st_sealing_key,
226
 
                                         &st_srv_kvno))) {
227
 
            status = "2ND_TKT_SERVER";
228
 
            goto cleanup;
229
 
        }
230
 
        errcode = krb5_decrypt_tkt_part(kdc_context, st_sealing_key,
231
 
                                       request->second_ticket[st_idx]);
232
 
        krb5_free_keyblock(kdc_context, st_sealing_key);
233
 
        if (errcode) {
234
 
            status = "2ND_TKT_DECRYPT";
235
 
            goto cleanup;
236
 
        }
237
 
        
238
 
        etype = request->second_ticket[st_idx]->enc_part2->session->enctype;
239
 
        if (!krb5_c_valid_enctype(etype)) {
240
 
            status = "BAD_ETYPE_IN_2ND_TKT";
241
 
            errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
242
 
            goto cleanup;
243
 
        }
244
 
        
245
 
        for (i = 0; i < request->nktypes; i++) {
246
 
            if (request->ktype[i] == etype) {
247
 
                useenctype = etype;
248
 
                break;
249
 
            }
250
 
        }
 
315
    if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY |
 
316
                        KDC_OPT_CNAME_IN_ADDL_TKT)) {
 
317
        krb5_keyblock *        st_sealing_key;
 
318
        krb5_kvno       st_srv_kvno;
 
319
        krb5_enctype    etype;
 
320
        krb5_db_entry    st_client;
 
321
        int             st_nprincs = 0;
 
322
 
 
323
        /*
 
324
         * Get the key for the second ticket, and decrypt it.
 
325
         */
 
326
        if ((errcode = kdc_get_server_key(request->second_ticket[st_idx],
 
327
                                          c_flags,
 
328
                                          TRUE, /* match_enctype */
 
329
                                          &st_client,
 
330
                                          &st_nprincs,
 
331
                                          &st_sealing_key,
 
332
                                          &st_srv_kvno))) {
 
333
            status = "2ND_TKT_SERVER";
 
334
            goto cleanup;
 
335
        }
 
336
        errcode = krb5_decrypt_tkt_part(kdc_context, st_sealing_key,
 
337
                                    request->second_ticket[st_idx]);
 
338
        krb5_free_keyblock(kdc_context, st_sealing_key);
 
339
        if (errcode) {
 
340
            status = "2ND_TKT_DECRYPT";
 
341
            krb5_db_free_principal(kdc_context, &st_client, st_nprincs);
 
342
            goto cleanup;
 
343
        }
 
344
        
 
345
        etype = request->second_ticket[st_idx]->enc_part2->session->enctype;
 
346
        if (!krb5_c_valid_enctype(etype)) {
 
347
            status = "BAD_ETYPE_IN_2ND_TKT";
 
348
            errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
 
349
            krb5_db_free_principal(kdc_context, &st_client, st_nprincs);
 
350
            goto cleanup;
 
351
        }
 
352
        
 
353
        for (i = 0; i < request->nktypes; i++) {
 
354
            if (request->ktype[i] == etype) {
 
355
                useenctype = etype;
 
356
                break;
 
357
            }
 
358
        }
 
359
 
 
360
        if (isflagset(request->kdc_options, KDC_OPT_CNAME_IN_ADDL_TKT)) {
 
361
            /* Do constrained delegation protocol and authorization checks */
 
362
            errcode = kdc_process_s4u2proxy_req(kdc_context,
 
363
                                                request,
 
364
                                                request->second_ticket[st_idx]->enc_part2,
 
365
                                                &st_client,
 
366
                                                header_ticket->enc_part2->client,
 
367
                                                request->server,
 
368
                                                &status);
 
369
            if (errcode)
 
370
                goto cleanup;
 
371
 
 
372
            setflag(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION);
 
373
 
 
374
            assert(krb5_is_tgs_principal(header_ticket->server));
 
375
 
 
376
            /* From now on, use evidence ticket as header ticket */
 
377
            header_enc_tkt = request->second_ticket[st_idx]->enc_part2;
 
378
 
 
379
            assert(c_nprincs == 0); /* assured by kdc_process_s4u2self_req() */
 
380
 
 
381
            client = st_client;
 
382
            c_nprincs = st_nprincs;
 
383
        } else {
 
384
            /* "client" is not used for user2user */
 
385
            krb5_db_free_principal(kdc_context, &st_client, st_nprincs);
 
386
        }
251
387
    }
252
388
 
253
389
    /*
254
390
     * Select the keytype for the ticket session key.
255
391
     */
256
392
    if ((useenctype == 0) &&
257
 
        (useenctype = select_session_keytype(kdc_context, &server,
258
 
                                             request->nktypes,
259
 
                                             request->ktype)) == 0) {
260
 
        /* unsupported ktype */
261
 
        status = "BAD_ENCRYPTION_TYPE";
262
 
        errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
263
 
        goto cleanup;
 
393
        (useenctype = select_session_keytype(kdc_context, &server,
 
394
        request->nktypes,
 
395
        request->ktype)) == 0) {
 
396
        /* unsupported ktype */
 
397
        status = "BAD_ENCRYPTION_TYPE";
 
398
        errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
 
399
        goto cleanup;
264
400
    }
265
401
    
266
402
    errcode = krb5_c_make_random_key(kdc_context, useenctype, &session_key);
267
403
 
268
404
    if (errcode) {
269
 
        /* random key failed */
270
 
        status = "RANDOM_KEY_FAILED";
271
 
        goto cleanup;
 
405
        /* random key failed */
 
406
        status = "RANDOM_KEY_FAILED";
 
407
        goto cleanup;
272
408
    }
273
409
 
274
 
    ticket_reply.server = request->server; /* XXX careful for realm... */
 
410
    authtime = header_enc_tkt->times.authtime;
 
411
 
 
412
    if (is_referral)
 
413
        ticket_reply.server = server.princ;
 
414
    else
 
415
        ticket_reply.server = request->server; /* XXX careful for realm... */
275
416
 
276
417
    enc_tkt_reply.flags = 0;
277
418
    enc_tkt_reply.times.starttime = 0;
278
419
 
 
420
    if (isflagset(server.attributes, KRB5_KDB_OK_AS_DELEGATE) &&
 
421
        !is_referral) {
 
422
        /* Ensure that we are not returning a referral */
 
423
        setflag(enc_tkt_reply.flags, TKT_FLG_OK_AS_DELEGATE);
 
424
    }
 
425
 
279
426
    /*
280
427
     * Fix header_ticket's starttime; if it's zero, fill in the
281
428
     * authtime's value.
282
429
     */
283
 
    if (!(header_ticket->enc_part2->times.starttime))
284
 
        header_ticket->enc_part2->times.starttime =
285
 
            header_ticket->enc_part2->times.authtime;
 
430
    if (!(header_enc_tkt->times.starttime))
 
431
        header_enc_tkt->times.starttime = header_enc_tkt->times.authtime;
286
432
 
287
433
    /* don't use new addresses unless forwarded, see below */
288
434
 
289
 
    enc_tkt_reply.caddrs = header_ticket->enc_part2->caddrs;
 
435
    enc_tkt_reply.caddrs = header_enc_tkt->caddrs;
290
436
    /* noaddrarray[0] = 0; */
291
 
    reply_encpart.caddrs = 0;           /* optional...don't put it in */
 
437
    reply_encpart.caddrs = 0;/* optional...don't put it in */
 
438
    reply_encpart.enc_padata = NULL;
292
439
 
293
440
    /* It should be noted that local policy may affect the  */
294
441
    /* processing of any of these flags.  For example, some */
295
442
    /* realms may refuse to issue renewable tickets         */
296
443
 
297
444
    if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE))
298
 
        setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
299
 
 
 
445
        setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
 
446
    if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
 
447
        if (!krb5_is_tgs_principal(server.princ) &&
 
448
            is_local_principal(server.princ)) {
 
449
            if (isflagset(server.attributes, KRB5_KDB_OK_TO_AUTH_AS_DELEGATE))
 
450
                setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
 
451
            else
 
452
                clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
 
453
        }
 
454
        if (isflagset(client.attributes, KRB5_KDB_DISALLOW_FORWARDABLE))
 
455
            clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
 
456
    }
300
457
    if (isflagset(request->kdc_options, KDC_OPT_FORWARDED)) {
301
 
        setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDED);
302
 
 
303
 
        /* include new addresses in ticket & reply */
304
 
 
305
 
        enc_tkt_reply.caddrs = request->addresses;
306
 
        reply_encpart.caddrs = request->addresses;
307
 
    }   
308
 
    if (isflagset(header_ticket->enc_part2->flags, TKT_FLG_FORWARDED))
309
 
        setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDED);
 
458
        setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDED);
 
459
 
 
460
        /* include new addresses in ticket & reply */
 
461
 
 
462
        enc_tkt_reply.caddrs = request->addresses;
 
463
        reply_encpart.caddrs = request->addresses;
 
464
    }        
 
465
    if (isflagset(header_enc_tkt->flags, TKT_FLG_FORWARDED))
 
466
        setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDED);
310
467
 
311
468
    if (isflagset(request->kdc_options, KDC_OPT_PROXIABLE))
312
 
        setflag(enc_tkt_reply.flags, TKT_FLG_PROXIABLE);
 
469
        setflag(enc_tkt_reply.flags, TKT_FLG_PROXIABLE);
313
470
 
314
471
    if (isflagset(request->kdc_options, KDC_OPT_PROXY)) {
315
 
        setflag(enc_tkt_reply.flags, TKT_FLG_PROXY);
316
 
 
317
 
        /* include new addresses in ticket & reply */
318
 
 
319
 
        enc_tkt_reply.caddrs = request->addresses;
320
 
        reply_encpart.caddrs = request->addresses;
 
472
        setflag(enc_tkt_reply.flags, TKT_FLG_PROXY);
 
473
 
 
474
        /* include new addresses in ticket & reply */
 
475
 
 
476
        enc_tkt_reply.caddrs = request->addresses;
 
477
        reply_encpart.caddrs = request->addresses;
321
478
    }
322
479
 
323
480
    if (isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE))
324
 
        setflag(enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);
 
481
        setflag(enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);
325
482
 
326
483
    if (isflagset(request->kdc_options, KDC_OPT_POSTDATED)) {
327
 
        setflag(enc_tkt_reply.flags, TKT_FLG_POSTDATED);
328
 
        setflag(enc_tkt_reply.flags, TKT_FLG_INVALID);
329
 
        enc_tkt_reply.times.starttime = request->from;
 
484
        setflag(enc_tkt_reply.flags, TKT_FLG_POSTDATED);
 
485
        setflag(enc_tkt_reply.flags, TKT_FLG_INVALID);
 
486
        enc_tkt_reply.times.starttime = request->from;
330
487
    } else
331
 
        enc_tkt_reply.times.starttime = kdc_time;
 
488
        enc_tkt_reply.times.starttime = kdc_time;
332
489
 
333
490
    if (isflagset(request->kdc_options, KDC_OPT_VALIDATE)) {
334
 
        /* BEWARE of allocation hanging off of ticket & enc_part2, it belongs
335
 
           to the caller */
336
 
        ticket_reply = *(header_ticket);
337
 
        enc_tkt_reply = *(header_ticket->enc_part2);
338
 
        clear(enc_tkt_reply.flags, TKT_FLG_INVALID);
 
491
        assert(isflagset(c_flags, KRB5_KDB_FLAGS_S4U) == 0);
 
492
        /* BEWARE of allocation hanging off of ticket & enc_part2, it belongs
 
493
           to the caller */
 
494
        ticket_reply = *(header_ticket);
 
495
        enc_tkt_reply = *(header_ticket->enc_part2);
 
496
        clear(enc_tkt_reply.flags, TKT_FLG_INVALID);
339
497
    }
340
498
 
341
499
    if (isflagset(request->kdc_options, KDC_OPT_RENEW)) {
342
 
        krb5_deltat old_life;
343
 
 
344
 
        /* BEWARE of allocation hanging off of ticket & enc_part2, it belongs
345
 
           to the caller */
346
 
        ticket_reply = *(header_ticket);
347
 
        enc_tkt_reply = *(header_ticket->enc_part2);
348
 
 
349
 
        old_life = enc_tkt_reply.times.endtime - enc_tkt_reply.times.starttime;
350
 
 
351
 
        enc_tkt_reply.times.starttime = kdc_time;
352
 
        enc_tkt_reply.times.endtime =
353
 
            min(header_ticket->enc_part2->times.renew_till,
354
 
                kdc_time + old_life);
 
500
        krb5_deltat old_life;
 
501
 
 
502
        assert(isflagset(c_flags, KRB5_KDB_FLAGS_S4U) == 0);
 
503
        /* BEWARE of allocation hanging off of ticket & enc_part2, it belongs
 
504
           to the caller */
 
505
        ticket_reply = *(header_ticket);
 
506
        enc_tkt_reply = *(header_ticket->enc_part2);
 
507
 
 
508
        old_life = enc_tkt_reply.times.endtime - enc_tkt_reply.times.starttime;
 
509
 
 
510
        enc_tkt_reply.times.starttime = kdc_time;
 
511
        enc_tkt_reply.times.endtime =
 
512
            min(header_ticket->enc_part2->times.renew_till,
 
513
                kdc_time + old_life);
355
514
    } else {
356
 
        /* not a renew request */
357
 
        enc_tkt_reply.times.starttime = kdc_time;
358
 
        until = (request->till == 0) ? kdc_infinity : request->till;
359
 
        enc_tkt_reply.times.endtime =
360
 
            min(until, min(enc_tkt_reply.times.starttime + server.max_life,
361
 
                           min(enc_tkt_reply.times.starttime + max_life_for_realm,
362
 
                               header_ticket->enc_part2->times.endtime)));
363
 
        if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE_OK) &&
364
 
            (enc_tkt_reply.times.endtime < request->till) &&
365
 
            isflagset(header_ticket->enc_part2->flags,
366
 
                  TKT_FLG_RENEWABLE)) {
367
 
            setflag(request->kdc_options, KDC_OPT_RENEWABLE);
368
 
            request->rtime =
369
 
                min(request->till,
370
 
                    header_ticket->enc_part2->times.renew_till);
371
 
        }
 
515
        /* not a renew request */
 
516
        enc_tkt_reply.times.starttime = kdc_time;
 
517
        until = (request->till == 0) ? kdc_infinity : request->till;
 
518
        enc_tkt_reply.times.endtime =
 
519
            min(until, min(enc_tkt_reply.times.starttime + server.max_life,
 
520
               min(enc_tkt_reply.times.starttime + max_life_for_realm,
 
521
                   header_enc_tkt->times.endtime)));
 
522
        if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE_OK) &&
 
523
            (enc_tkt_reply.times.endtime < request->till) &&
 
524
            isflagset(header_enc_tkt->flags, TKT_FLG_RENEWABLE)) {
 
525
            setflag(request->kdc_options, KDC_OPT_RENEWABLE);
 
526
            request->rtime =
 
527
                min(request->till, header_enc_tkt->times.renew_till);
 
528
        }
372
529
    }
373
530
    rtime = (request->rtime == 0) ? kdc_infinity : request->rtime;
374
531
 
375
532
    if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE)) {
376
 
        /* already checked above in policy check to reject request for a
377
 
           renewable ticket using a non-renewable ticket */
378
 
        setflag(enc_tkt_reply.flags, TKT_FLG_RENEWABLE);
379
 
        enc_tkt_reply.times.renew_till =
380
 
            min(rtime,
381
 
                min(header_ticket->enc_part2->times.renew_till,
382
 
                    enc_tkt_reply.times.starttime +
383
 
                    min(server.max_renewable_life,
384
 
                        max_renewable_life_for_realm)));
 
533
        /* already checked above in policy check to reject request for a
 
534
           renewable ticket using a non-renewable ticket */
 
535
        setflag(enc_tkt_reply.flags, TKT_FLG_RENEWABLE);
 
536
        enc_tkt_reply.times.renew_till =
 
537
                        min(rtime,
 
538
                            min(header_enc_tkt->times.renew_till,
 
539
                                enc_tkt_reply.times.starttime +
 
540
                                min(server.max_renewable_life,
 
541
                                max_renewable_life_for_realm)));
385
542
    } else {
386
 
        enc_tkt_reply.times.renew_till = 0;
 
543
        enc_tkt_reply.times.renew_till = 0;
387
544
    }
388
545
    
389
546
    /*
390
547
     * Set authtime to be the same as header_ticket's
391
548
     */
392
 
    enc_tkt_reply.times.authtime = header_ticket->enc_part2->times.authtime;
 
549
    enc_tkt_reply.times.authtime = header_enc_tkt->times.authtime;
393
550
    
394
551
    /*
395
552
     * Propagate the preauthentication flags through to the returned ticket.
396
553
     */
397
 
    if (isflagset(header_ticket->enc_part2->flags, TKT_FLG_PRE_AUTH))
398
 
        setflag(enc_tkt_reply.flags, TKT_FLG_PRE_AUTH);
 
554
    if (isflagset(header_enc_tkt->flags, TKT_FLG_PRE_AUTH))
 
555
        setflag(enc_tkt_reply.flags, TKT_FLG_PRE_AUTH);
399
556
 
400
 
    if (isflagset(header_ticket->enc_part2->flags, TKT_FLG_HW_AUTH))
401
 
        setflag(enc_tkt_reply.flags, TKT_FLG_HW_AUTH);
 
557
    if (isflagset(header_enc_tkt->flags, TKT_FLG_HW_AUTH))
 
558
        setflag(enc_tkt_reply.flags, TKT_FLG_HW_AUTH);
402
559
    
403
560
    /* starttime is optional, and treated as authtime if not present.
404
561
       so we can nuke it if it matches */
405
562
    if (enc_tkt_reply.times.starttime == enc_tkt_reply.times.authtime)
406
 
        enc_tkt_reply.times.starttime = 0;
407
 
 
408
 
    /* assemble any authorization data */
409
 
    if (request->authorization_data.ciphertext.data) {
410
 
        krb5_data scratch;
411
 
 
412
 
        scratch.length = request->authorization_data.ciphertext.length;
413
 
        if (!(scratch.data =
414
 
              malloc(request->authorization_data.ciphertext.length))) {
415
 
            status = "AUTH_NOMEM";
416
 
            errcode = ENOMEM;
417
 
            goto cleanup;
418
 
        }
419
 
 
420
 
        if ((errcode = krb5_c_decrypt(kdc_context,
421
 
                                      header_ticket->enc_part2->session,
422
 
                                      KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY,
423
 
                                      0, &request->authorization_data,
424
 
                                      &scratch))) {
425
 
            status = "AUTH_ENCRYPT_FAIL";
426
 
            free(scratch.data);
427
 
            goto cleanup;
428
 
        }
429
 
 
430
 
        /* scratch now has the authorization data, so we decode it */
431
 
        errcode = decode_krb5_authdata(&scratch, &(request->unenc_authdata));
432
 
        free(scratch.data);
433
 
        if (errcode) {
434
 
            status = "AUTH_DECODE";
435
 
            goto cleanup;
436
 
        }
437
 
 
438
 
        if ((errcode =
439
 
             concat_authorization_data(request->unenc_authdata,
440
 
                                       header_ticket->enc_part2->authorization_data, 
441
 
                                       &enc_tkt_reply.authorization_data))) {
442
 
            status = "CONCAT_AUTH";
443
 
            goto cleanup;
444
 
        }
445
 
    } else
446
 
        enc_tkt_reply.authorization_data =
447
 
            header_ticket->enc_part2->authorization_data;
 
563
        enc_tkt_reply.times.starttime = 0;
 
564
 
 
565
    if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
 
566
        errcode = krb5_unparse_name(kdc_context, for_user->user, &s4u_name);
 
567
    } else if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION)) {
 
568
        errcode = krb5_unparse_name(kdc_context, header_enc_tkt->client, &s4u_name);
 
569
    } else {
 
570
        errcode = 0;
 
571
    }
 
572
    if (errcode) {
 
573
        status = "UNPARSING S4U CLIENT";
 
574
        goto cleanup;
 
575
    }
 
576
 
 
577
    if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) {
 
578
        krb5_enc_tkt_part *t2enc = request->second_ticket[st_idx]->enc_part2;
 
579
        encrypting_key = *(t2enc->session);
 
580
    } else {
 
581
        /*
 
582
         * Find the server key
 
583
         */
 
584
        if ((errcode = krb5_dbe_find_enctype(kdc_context, &server,
 
585
                             -1, /* ignore keytype */
 
586
                                             -1, /* Ignore salttype */
 
587
                                             0,/* Get highest kvno */
 
588
                                             &server_key))) {
 
589
            status = "FINDING_SERVER_KEY";
 
590
            goto cleanup;
 
591
        }
 
592
 
 
593
        if ((errcode = krb5_dbe_find_mkey(kdc_context, master_keylist, &server,
 
594
                                          &mkey_ptr))) {
 
595
            krb5_keylist_node *tmp_mkey_list;
 
596
            /* try refreshing master key list */
 
597
            /* XXX it would nice if we had the mkvno here for optimization */
 
598
            if (krb5_db_fetch_mkey_list(kdc_context, master_princ,
 
599
                                        &master_keyblock, 0, &tmp_mkey_list) == 0) {
 
600
                krb5_dbe_free_key_list(kdc_context, master_keylist);
 
601
                master_keylist = tmp_mkey_list;
 
602
                if ((errcode = krb5_dbe_find_mkey(kdc_context, master_keylist,
 
603
                                                  &server, &mkey_ptr))) {
 
604
                    status = "FINDING_MASTER_KEY";
 
605
                    goto cleanup;
 
606
                }
 
607
            } else {
 
608
                status = "FINDING_MASTER_KEY";
 
609
                goto cleanup;
 
610
            }
 
611
        }
 
612
 
 
613
        /* convert server.key into a real key (it may be encrypted
 
614
         *        in the database) */
 
615
        if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context,
 
616
                                                   mkey_ptr, 
 
617
                                                   server_key, &encrypting_key,
 
618
                                                   NULL))) {
 
619
            status = "DECRYPT_SERVER_KEY";
 
620
            goto cleanup;
 
621
        }
 
622
    }
 
623
 
 
624
    if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION)) {
 
625
        /*
 
626
         * Don't allow authorization data to be disabled if constrained
 
627
         * delegation is requested. We don't want to deny the server
 
628
         * the ability to validate that delegation was used.
 
629
         */
 
630
        clear(server.attributes, KRB5_KDB_NO_AUTH_DATA_REQUIRED);
 
631
    }
 
632
    if (isflagset(server.attributes, KRB5_KDB_NO_AUTH_DATA_REQUIRED) == 0) {
 
633
        /*
 
634
         * If we are not doing protocol transition/constrained delegation
 
635
         * and there was no authorization data included, try to lookup
 
636
         * the client principal as it may be mapped to a local account.
 
637
         *
 
638
         * Always validate authorization data for constrained delegation
 
639
         * because we must validate the KDC signatures.
 
640
         */
 
641
        if (!isflagset(c_flags, KRB5_KDB_FLAGS_S4U) &&
 
642
            header_enc_tkt->authorization_data == NULL) {
 
643
 
 
644
            /* Generate authorization data so we can include it in ticket */
 
645
            setflag(c_flags, KRB5_KDB_FLAG_INCLUDE_PAC);
 
646
            /* Map principals from foreign (possibly non-AD) realms */
 
647
            setflag(c_flags, KRB5_KDB_FLAG_MAP_PRINCIPALS);
 
648
 
 
649
            assert(c_nprincs == 0); /* should not have been looked up already */
 
650
 
 
651
            c_nprincs = 1;
 
652
            errcode = krb5_db_get_principal_ext(kdc_context,
 
653
                                                header_enc_tkt->client,
 
654
                                                c_flags,
 
655
                                                &client,
 
656
                                                &c_nprincs,
 
657
                                                &more);
 
658
            /*
 
659
             * We can ignore errors because the principal may be a
 
660
             * valid cross-realm principal for which we have no local
 
661
             * mapping. But we do want to check that at most one entry
 
662
             * was returned.
 
663
             */
 
664
            if (errcode == 0 && (more || c_nprincs > 1)) {
 
665
                errcode = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
 
666
                goto cleanup;
 
667
            } else if (errcode) {
 
668
                c_nprincs = 0;
 
669
            }
 
670
        }
 
671
    }
 
672
 
 
673
    enc_tkt_reply.authorization_data = NULL;
 
674
 
 
675
    if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) &&
 
676
        is_local_principal(header_enc_tkt->client))
 
677
        enc_tkt_reply.client = for_user->user;
 
678
    else
 
679
        enc_tkt_reply.client = header_enc_tkt->client;
 
680
 
 
681
    errcode = handle_authdata(kdc_context,
 
682
                              c_flags,
 
683
                              (c_nprincs != 0) ? &client : NULL,
 
684
                              &server,
 
685
                              (k_nprincs != 0) ? &krbtgt : NULL,
 
686
                              subkey != NULL ? subkey :
 
687
                              header_ticket->enc_part2->session,
 
688
                              &encrypting_key, /* U2U or server key */
 
689
                              pkt,
 
690
                              request,
 
691
                              for_user ? for_user->user : NULL,
 
692
                              header_enc_tkt,
 
693
                              &enc_tkt_reply);
 
694
    if (errcode) {
 
695
        krb5_klog_syslog(LOG_INFO, "TGS_REQ : handle_authdata (%d)", errcode);
 
696
        status = "HANDLE_AUTHDATA";
 
697
        goto cleanup;
 
698
    }
 
699
 
 
700
    if (is_referral && isflagset(s_flags, KRB5_KDB_FLAG_CANONICALIZE)) {
 
701
        errcode = return_svr_referral_data(kdc_context,
 
702
                                           &server, &reply_encpart);
 
703
        if (errcode) {
 
704
            status = "KDC_RETURN_ENC_PADATA";
 
705
            goto cleanup;
 
706
        }
 
707
    }
448
708
 
449
709
    enc_tkt_reply.session = &session_key;
450
 
    enc_tkt_reply.client = header_ticket->enc_part2->client;
451
710
    enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
452
711
    enc_tkt_reply.transited.tr_contents = empty_string; /* equivalent of "" */
453
712
 
461
720
 
462
721
    /* realm compare is like strcmp, but knows how to deal with these args */
463
722
    if (realm_compare(header_ticket->server, tgs_server) ||
464
 
        realm_compare(header_ticket->server, enc_tkt_reply.client)) {
465
 
        /* tgt issued by local realm or issued by realm of client */
466
 
        enc_tkt_reply.transited = header_ticket->enc_part2->transited;
 
723
        realm_compare(header_ticket->server, enc_tkt_reply.client)) {
 
724
        /* tgt issued by local realm or issued by realm of client */
 
725
        enc_tkt_reply.transited = header_enc_tkt->transited;
467
726
    } else {
468
 
        /* tgt issued by some other realm and not the realm of the client */
469
 
        /* assemble new transited field into allocated storage */
470
 
        if (header_ticket->enc_part2->transited.tr_type !=
471
 
            KRB5_DOMAIN_X500_COMPRESS) {
472
 
            status = "BAD_TRTYPE";
473
 
            errcode = KRB5KDC_ERR_TRTYPE_NOSUPP;
474
 
            goto cleanup;
475
 
        }
476
 
        enc_tkt_transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
477
 
        enc_tkt_transited.magic = 0;
478
 
        enc_tkt_transited.tr_contents.magic = 0;
479
 
        enc_tkt_transited.tr_contents.data = 0;
480
 
        enc_tkt_transited.tr_contents.length = 0;
481
 
        enc_tkt_reply.transited = enc_tkt_transited;
482
 
        if ((errcode =
483
 
             add_to_transited(&header_ticket->enc_part2->transited.tr_contents,
484
 
                              &enc_tkt_reply.transited.tr_contents,
485
 
                              header_ticket->server,
486
 
                              enc_tkt_reply.client,
487
 
                              request->server))) {
488
 
            status = "ADD_TR_FAIL";
489
 
            goto cleanup;
490
 
        }
491
 
        newtransited = 1;
 
727
        /* tgt issued by some other realm and not the realm of the client */
 
728
        /* assemble new transited field into allocated storage */
 
729
        if (header_enc_tkt->transited.tr_type !=
 
730
            KRB5_DOMAIN_X500_COMPRESS) {
 
731
            status = "BAD_TRTYPE";
 
732
            errcode = KRB5KDC_ERR_TRTYPE_NOSUPP;
 
733
            goto cleanup;
 
734
        }
 
735
        enc_tkt_transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
 
736
        enc_tkt_transited.magic = 0;
 
737
        enc_tkt_transited.tr_contents.magic = 0;
 
738
        enc_tkt_transited.tr_contents.data = 0;
 
739
        enc_tkt_transited.tr_contents.length = 0;
 
740
        enc_tkt_reply.transited = enc_tkt_transited;
 
741
        if ((errcode =
 
742
            add_to_transited(&header_enc_tkt->transited.tr_contents,
 
743
                             &enc_tkt_reply.transited.tr_contents,
 
744
                             header_ticket->server,
 
745
                             enc_tkt_reply.client,
 
746
                             request->server))) {
 
747
                                 status = "ADD_TR_FAIL";
 
748
                                 goto cleanup;
 
749
        }
 
750
        newtransited = 1;
 
751
    }
 
752
    if (isflagset(c_flags, KRB5_KDB_FLAG_CROSS_REALM)) {
 
753
        errcode = validate_transit_path(kdc_context, header_enc_tkt->client,
 
754
        &server,
 
755
        (k_nprincs != 0) ? &krbtgt : NULL);
 
756
        if (errcode) {
 
757
            status = "NON_TRANSITIVE";
 
758
            goto cleanup;
 
759
        }
492
760
    }
493
761
    if (!isflagset (request->kdc_options, KDC_OPT_DISABLE_TRANSITED_CHECK)) {
494
 
        unsigned int tlen;
495
 
        char *tdots;
496
 
 
497
 
        errcode = krb5_check_transited_list (kdc_context,
498
 
                                             &enc_tkt_reply.transited.tr_contents,
499
 
                                             krb5_princ_realm (kdc_context, header_ticket->enc_part2->client),
500
 
                                             krb5_princ_realm (kdc_context, request->server));
501
 
        tlen = enc_tkt_reply.transited.tr_contents.length;
502
 
        tdots = tlen > 125 ? "..." : "";
503
 
        tlen = tlen > 125 ? 125 : tlen;
504
 
 
505
 
        if (errcode == 0) {
506
 
            setflag (enc_tkt_reply.flags, TKT_FLG_TRANSIT_POLICY_CHECKED);
507
 
        } else if (errcode == KRB5KRB_AP_ERR_ILL_CR_TKT)
508
 
            krb5_klog_syslog (LOG_INFO,
509
 
                              "bad realm transit path from '%s' to '%s' "
510
 
                              "via '%.*s%s'",
511
 
                              cname ? cname : "<unknown client>",
512
 
                              sname ? sname : "<unknown server>",
513
 
                              tlen,
514
 
                              enc_tkt_reply.transited.tr_contents.data,
515
 
                              tdots);
516
 
        else {
517
 
            const char *emsg = krb5_get_error_message(kdc_context, errcode);
518
 
            krb5_klog_syslog (LOG_ERR,
519
 
                              "unexpected error checking transit from "
520
 
                              "'%s' to '%s' via '%.*s%s': %s",
521
 
                              cname ? cname : "<unknown client>",
522
 
                              sname ? sname : "<unknown server>",
523
 
                              tlen,
524
 
                              enc_tkt_reply.transited.tr_contents.data,
525
 
                              tdots, emsg);
526
 
            krb5_free_error_message(kdc_context, emsg);
527
 
        }
 
762
        unsigned int tlen;
 
763
        char *tdots;
 
764
 
 
765
        errcode = kdc_check_transited_list (kdc_context,
 
766
                                            &enc_tkt_reply.transited.tr_contents,
 
767
                                            krb5_princ_realm (kdc_context, header_enc_tkt->client),
 
768
                                            krb5_princ_realm (kdc_context, request->server));
 
769
        tlen = enc_tkt_reply.transited.tr_contents.length;
 
770
        tdots = tlen > 125 ? "..." : "";
 
771
        tlen = tlen > 125 ? 125 : tlen;
 
772
 
 
773
        if (errcode == 0) {
 
774
            setflag (enc_tkt_reply.flags, TKT_FLG_TRANSIT_POLICY_CHECKED);
 
775
        } else if (errcode == KRB5KRB_AP_ERR_ILL_CR_TKT)
 
776
            krb5_klog_syslog (LOG_INFO,
 
777
                              "bad realm transit path from '%s' to '%s' "
 
778
                              "via '%.*s%s'",
 
779
                              cname ? cname : "<unknown client>",
 
780
                              sname ? sname : "<unknown server>",
 
781
                              tlen,
 
782
                              enc_tkt_reply.transited.tr_contents.data,
 
783
                              tdots);
 
784
        else {
 
785
            emsg = krb5_get_error_message(kdc_context, errcode);
 
786
            krb5_klog_syslog (LOG_ERR,
 
787
                              "unexpected error checking transit from "
 
788
                              "'%s' to '%s' via '%.*s%s': %s",
 
789
                              cname ? cname : "<unknown client>",
 
790
                              sname ? sname : "<unknown server>",
 
791
                              tlen,
 
792
                              enc_tkt_reply.transited.tr_contents.data,
 
793
                              tdots, emsg);
 
794
            krb5_free_error_message(kdc_context, emsg);
 
795
            emsg = NULL;
 
796
        }
528
797
    } else
529
 
        krb5_klog_syslog (LOG_INFO, "not checking transit path");
 
798
        krb5_klog_syslog (LOG_INFO, "not checking transit path");
530
799
    if (reject_bad_transit
531
 
        && !isflagset (enc_tkt_reply.flags, TKT_FLG_TRANSIT_POLICY_CHECKED)) {
532
 
        errcode = KRB5KDC_ERR_POLICY;
533
 
        status = "BAD_TRANSIT";
534
 
        goto cleanup;
 
800
        && !isflagset (enc_tkt_reply.flags, TKT_FLG_TRANSIT_POLICY_CHECKED)) {
 
801
        errcode = KRB5KDC_ERR_POLICY;
 
802
        status = "BAD_TRANSIT";
 
803
        goto cleanup;
535
804
    }
536
805
 
537
806
    ticket_reply.enc_part2 = &enc_tkt_reply;
543
812
     * the second ticket.
544
813
     */
545
814
    if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) {
546
 
        /*
547
 
         * Make sure the client for the second ticket matches
548
 
         * requested server.
549
 
         */
550
 
        krb5_enc_tkt_part *t2enc = request->second_ticket[st_idx]->enc_part2;
551
 
        krb5_principal client2 = t2enc->client;
552
 
        if (!krb5_principal_compare(kdc_context, request->server, client2)) {
553
 
                if ((errcode = krb5_unparse_name(kdc_context, client2, &tmp)))
554
 
                        tmp = 0;
555
 
                if (tmp != NULL)
556
 
                    limit_string(tmp);
 
815
        /*
 
816
         * Make sure the client for the second ticket matches
 
817
         * requested server.
 
818
         */
 
819
        krb5_enc_tkt_part *t2enc = request->second_ticket[st_idx]->enc_part2;
 
820
        krb5_principal client2 = t2enc->client;
 
821
        if (!krb5_principal_compare(kdc_context, request->server, client2)) {
 
822
            if ((errcode = krb5_unparse_name(kdc_context, client2, &altcname)))
 
823
                altcname = 0;
 
824
            if (altcname != NULL)
 
825
                limit_string(altcname);
557
826
 
558
 
                krb5_klog_syslog(LOG_INFO,
559
 
                                 "TGS_REQ %s: 2ND_TKT_MISMATCH: "
560
 
                                 "authtime %d, %s for %s, 2nd tkt client %s",
561
 
                                 fromstring, authtime,
562
 
                                 cname ? cname : "<unknown client>",
563
 
                                 sname ? sname : "<unknown server>",
564
 
                                 tmp ? tmp : "<unknown>");
565
 
                errcode = KRB5KDC_ERR_SERVER_NOMATCH;
566
 
                goto cleanup;
567
 
        }
568
 
            
569
 
        ticket_reply.enc_part.kvno = 0;
570
 
        ticket_reply.enc_part.enctype = t2enc->session->enctype;
571
 
        if ((errcode = krb5_encrypt_tkt_part(kdc_context, t2enc->session,
572
 
                                             &ticket_reply))) {
573
 
            status = "2ND_TKT_ENCRYPT";
574
 
            goto cleanup;
575
 
        }
576
 
        st_idx++;
 
827
            errcode = KRB5KDC_ERR_SERVER_NOMATCH;
 
828
            status = "2ND_TKT_MISMATCH";
 
829
            goto cleanup;
 
830
        }
 
831
            
 
832
        ticket_kvno = 0;
 
833
        ticket_reply.enc_part.enctype = t2enc->session->enctype;
 
834
        st_idx++;
577
835
    } else {
578
 
        /*
579
 
         * Find the server key
580
 
         */
581
 
        if ((errcode = krb5_dbe_find_enctype(kdc_context, &server,
582
 
                                             -1, /* ignore keytype */
583
 
                                             -1, /* Ignore salttype */
584
 
                                             0,         /* Get highest kvno */
585
 
                                             &server_key))) {
586
 
            status = "FINDING_SERVER_KEY";
587
 
            goto cleanup;
588
 
        }
589
 
        /* convert server.key into a real key (it may be encrypted
590
 
         *        in the database) */
591
 
        if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context,
592
 
                                                   &master_keyblock, 
593
 
                                                   server_key, &encrypting_key,
594
 
                                                   NULL))) {
595
 
            status = "DECRYPT_SERVER_KEY";
596
 
            goto cleanup;
597
 
        }
598
 
        errcode = krb5_encrypt_tkt_part(kdc_context, &encrypting_key,
599
 
                                        &ticket_reply);
600
 
        krb5_free_keyblock_contents(kdc_context, &encrypting_key);
601
 
        if (errcode) {
602
 
            status = "TKT_ENCRYPT";
603
 
            goto cleanup;
604
 
        }
605
 
        ticket_reply.enc_part.kvno = server_key->key_data_kvno;
 
836
        ticket_kvno = server_key->key_data_kvno;
606
837
    }
607
838
 
 
839
    errcode = krb5_encrypt_tkt_part(kdc_context, &encrypting_key,
 
840
                    &ticket_reply);
 
841
    if (!isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY))
 
842
        krb5_free_keyblock_contents(kdc_context, &encrypting_key);
 
843
    if (errcode) {
 
844
        status = "TKT_ENCRYPT";
 
845
        goto cleanup;
 
846
    }
 
847
    ticket_reply.enc_part.kvno = ticket_kvno;
608
848
    /* Start assembling the response */
609
849
    reply.msg_type = KRB5_TGS_REP;
610
 
    reply.padata = 0;           /* always */
611
 
    reply.client = header_ticket->enc_part2->client;
612
 
    reply.enc_part.kvno = 0;            /* We are using the session key */
 
850
    reply.padata = 0;/* always */
 
851
    reply.client = enc_tkt_reply.client;
 
852
    reply.enc_part.kvno = 0;/* We are using the session key */
613
853
    reply.ticket = &ticket_reply;
614
854
 
615
855
    reply_encpart.session = &session_key;
618
858
    /* copy the time fields EXCEPT for authtime; its location
619
859
       is used for ktime */
620
860
    reply_encpart.times = enc_tkt_reply.times;
621
 
    reply_encpart.times.authtime = header_ticket->enc_part2->times.authtime;
 
861
    reply_encpart.times.authtime = header_enc_tkt->times.authtime;
622
862
 
623
863
    /* starttime is optional, and treated as authtime if not present.
624
864
       so we can nuke it if it matches */
625
865
    if (enc_tkt_reply.times.starttime == enc_tkt_reply.times.authtime)
626
 
        enc_tkt_reply.times.starttime = 0;
 
866
        enc_tkt_reply.times.starttime = 0;
627
867
 
628
868
    nolrentry.lr_type = KRB5_LRQ_NONE;
629
869
    nolrentry.value = 0;
630
870
    nolrarray[0] = &nolrentry;
631
871
    nolrarray[1] = 0;
632
 
    reply_encpart.last_req = nolrarray; /* not available for TGS reqs */
633
 
    reply_encpart.key_exp = 0;          /* ditto */
 
872
    reply_encpart.last_req = nolrarray;        /* not available for TGS reqs */
 
873
    reply_encpart.key_exp = 0;/* ditto */
634
874
    reply_encpart.flags = enc_tkt_reply.flags;
635
875
    reply_encpart.server = ticket_reply.server;
636
876
    
638
878
       in the AP_REQ */
639
879
 
640
880
    reply.enc_part.enctype = subkey ? subkey->enctype :
641
 
                    header_ticket->enc_part2->session->enctype;
642
 
    errcode = krb5_encode_kdc_rep(kdc_context, KRB5_TGS_REP, &reply_encpart, 
643
 
                                  subkey ? 1 : 0,
644
 
                                  subkey ? subkey :
645
 
                                  header_ticket->enc_part2->session,
646
 
                                  &reply, response);
647
 
    if (errcode) {
648
 
        status = "ENCODE_KDC_REP";
 
881
    header_ticket->enc_part2->session->enctype;
 
882
    errcode  = kdc_fast_response_handle_padata(state, request, &reply,
 
883
                                               subkey?subkey->enctype:header_ticket->enc_part2->session->enctype);
 
884
    if (errcode !=0 ) {
 
885
        status = "Preparing FAST padata";
 
886
        goto cleanup;
 
887
    }
 
888
    errcode =kdc_fast_handle_reply_key(state, subkey?subkey:header_ticket->enc_part2->session, &reply_key);
 
889
    if (errcode) {
 
890
      status  = "generating reply key";
 
891
      goto cleanup;
 
892
    }
 
893
            errcode = krb5_encode_kdc_rep(kdc_context, KRB5_TGS_REP, &reply_encpart, 
 
894
                  subkey ? 1 : 0,
 
895
                                          reply_key,
 
896
                  &reply, response);
 
897
    if (errcode) {
 
898
        status = "ENCODE_KDC_REP";
649
899
    } else {
650
 
        status = "ISSUE";
 
900
        status = "ISSUE";
651
901
    }
652
902
 
653
903
    memset(ticket_reply.enc_part.ciphertext.data, 0,
654
 
           ticket_reply.enc_part.ciphertext.length);
 
904
           ticket_reply.enc_part.ciphertext.length);
655
905
    free(ticket_reply.enc_part.ciphertext.data);
656
906
    /* these parts are left on as a courtesy from krb5_encode_kdc_rep so we
657
907
       can use them in raw form if needed.  But, we don't... */
658
908
    memset(reply.enc_part.ciphertext.data, 0,
659
 
           reply.enc_part.ciphertext.length);
 
909
           reply.enc_part.ciphertext.length);
660
910
    free(reply.enc_part.ciphertext.data);
661
911
    
662
912
cleanup:
663
 
    if (status) {
664
 
        const char * emsg = NULL;
665
 
        if (!errcode)
666
 
            rep_etypes2str(rep_etypestr, sizeof(rep_etypestr), &reply);
667
 
        if (errcode) 
668
 
            emsg = krb5_get_error_message (kdc_context, errcode);
669
 
        krb5_klog_syslog(LOG_INFO,
670
 
                         "TGS_REQ (%s) %s: %s: authtime %d, "
671
 
                         "%s%s %s for %s%s%s",
672
 
                         ktypestr,
673
 
                         fromstring, status, authtime,
674
 
                         !errcode ? rep_etypestr : "",
675
 
                         !errcode ? "," : "",
676
 
                         cname ? cname : "<unknown client>",
677
 
                         sname ? sname : "<unknown server>",
678
 
                         errcode ? ", " : "",
679
 
                         errcode ? emsg : "");
680
 
        if (errcode)
681
 
            krb5_free_error_message (kdc_context, emsg);
 
913
    assert(status != NULL);
 
914
    if (reply_key)
 
915
      krb5_free_keyblock(kdc_context, reply_key);
 
916
    if (errcode) 
 
917
        emsg = krb5_get_error_message (kdc_context, errcode);
 
918
    log_tgs_req(from, request, &reply, cname, sname, altcname, authtime,
 
919
                c_flags, s4u_name, status, errcode, emsg);
 
920
    if (errcode) {
 
921
        krb5_free_error_message (kdc_context, emsg);
 
922
        emsg = NULL;
682
923
    }
683
 
    
 
924
 
684
925
    if (errcode) {
685
926
        int got_err = 0;
686
 
        if (status == 0) {
687
 
            status = krb5_get_error_message (kdc_context, errcode);
688
 
            got_err = 1;
689
 
        }
690
 
        errcode -= ERROR_TABLE_BASE_krb5;
691
 
        if (errcode < 0 || errcode > 128)
692
 
            errcode = KRB_ERR_GENERIC;
693
 
            
694
 
        retval = prepare_error_tgs(request, header_ticket, errcode,
695
 
                                   fromstring, response, status);
696
 
        if (got_err) {
697
 
            krb5_free_error_message (kdc_context, status);
698
 
            status = 0;
699
 
        }
 
927
        if (status == 0) {
 
928
            status = krb5_get_error_message (kdc_context, errcode);
 
929
            got_err = 1;
 
930
        }
 
931
        errcode -= ERROR_TABLE_BASE_krb5;
 
932
        if (errcode < 0 || errcode > 128)
 
933
            errcode = KRB_ERR_GENERIC;
 
934
            
 
935
        retval = prepare_error_tgs(state, request, header_ticket, errcode,
 
936
        nprincs ? server.princ : NULL,
 
937
                   response, status);
 
938
        if (got_err) {
 
939
            krb5_free_error_message (kdc_context, status);
 
940
            status = 0;
 
941
        }
700
942
    }
701
943
    
702
 
    if (header_ticket)
703
 
        krb5_free_ticket(kdc_context, header_ticket);
704
 
    if (request)
705
 
        krb5_free_kdc_req(kdc_context, request);
706
 
    if (cname)
707
 
        free(cname);
708
 
    if (sname)
709
 
        free(sname);
710
 
    if (nprincs)
711
 
        krb5_db_free_principal(kdc_context, &server, 1);
712
 
    if (session_key.contents)
713
 
        krb5_free_keyblock_contents(kdc_context, &session_key);
 
944
    if (header_ticket != NULL)
 
945
        krb5_free_ticket(kdc_context, header_ticket);
 
946
    if (request != NULL)
 
947
        krb5_free_kdc_req(kdc_context, request);
 
948
    if (state)
 
949
        kdc_free_rstate(state);
 
950
    if (cname != NULL)
 
951
        free(cname);
 
952
    if (sname != NULL)
 
953
        free(sname);
 
954
    if (nprincs != 0)
 
955
        krb5_db_free_principal(kdc_context, &server, 1);
 
956
    if (session_key.contents != NULL)
 
957
        krb5_free_keyblock_contents(kdc_context, &session_key);
714
958
    if (newtransited)
715
 
        free(enc_tkt_reply.transited.tr_contents.data); 
 
959
        free(enc_tkt_reply.transited.tr_contents.data);
 
960
    if (k_nprincs)
 
961
        krb5_db_free_principal(kdc_context, &krbtgt, k_nprincs);
 
962
    if (c_nprincs)
 
963
        krb5_db_free_principal(kdc_context, &client, c_nprincs);
 
964
    if (for_user != NULL)
 
965
        krb5_free_pa_for_user(kdc_context, for_user);
 
966
    if (kdc_issued_auth_data != NULL)
 
967
        krb5_free_authdata(kdc_context, kdc_issued_auth_data);
 
968
    if (s4u_name != NULL)
 
969
        free(s4u_name);
 
970
    if (subkey != NULL)
 
971
        krb5_free_keyblock(kdc_context, subkey);
716
972
 
717
973
    return retval;
718
974
}
719
975
 
720
976
static krb5_error_code
721
 
prepare_error_tgs (krb5_kdc_req *request, krb5_ticket *ticket, int error,
722
 
                   const char *ident, krb5_data **response, const char *status)
 
977
prepare_error_tgs (struct kdc_request_state *state,
 
978
                   krb5_kdc_req *request, krb5_ticket *ticket, int error,
 
979
                   krb5_principal canon_server,
 
980
                   krb5_data **response, const char *status)
723
981
{
724
982
    krb5_error errpkt;
725
 
    krb5_error_code retval;
 
983
    krb5_error_code retval = 0;
726
984
    krb5_data *scratch;
727
985
 
728
986
    errpkt.ctime = request->nonce;
729
987
    errpkt.cusec = 0;
730
988
 
731
989
    if ((retval = krb5_us_timeofday(kdc_context, &errpkt.stime,
732
 
                                    &errpkt.susec)))
733
 
        return(retval);
 
990
                    &errpkt.susec)))
 
991
        return(retval);
734
992
    errpkt.error = error;
735
993
    errpkt.server = request->server;
736
994
    if (ticket && ticket->enc_part2)
737
 
        errpkt.client = ticket->enc_part2->client;
 
995
        errpkt.client = ticket->enc_part2->client;
738
996
    else
739
 
        errpkt.client = 0;
 
997
        errpkt.client = NULL;
740
998
    errpkt.text.length = strlen(status) + 1;
741
 
    if (!(errpkt.text.data = malloc(errpkt.text.length)))
742
 
        return ENOMEM;
743
 
    (void) strcpy(errpkt.text.data, status);
744
 
 
 
999
    if (!(errpkt.text.data = strdup(status)))
 
1000
        return ENOMEM;
 
1001
    
745
1002
    if (!(scratch = (krb5_data *)malloc(sizeof(*scratch)))) {
 
1003
        free(errpkt.text.data);
 
1004
        return ENOMEM;
 
1005
    }
 
1006
    errpkt.e_data.length = 0;
 
1007
    errpkt.e_data.data = NULL;
 
1008
    if (state)
 
1009
        retval = kdc_fast_handle_error(kdc_context, state, request, NULL, &errpkt);
 
1010
    if (retval) {
 
1011
        free(scratch);
746
1012
        free(errpkt.text.data);
747
 
        return ENOMEM;
 
1013
        return retval;
748
1014
    }
749
 
    errpkt.e_data.length = 0;
750
 
    errpkt.e_data.data = 0;
751
 
 
752
1015
    retval = krb5_mk_error(kdc_context, &errpkt, scratch);
753
1016
    free(errpkt.text.data);
754
1017
    if (retval)
755
 
        free(scratch);
 
1018
        free(scratch);
756
1019
    else
757
 
        *response = scratch;
 
1020
        *response = scratch;
758
1021
 
759
1022
    return retval;
760
1023
}
766
1029
 */
767
1030
static void
768
1031
find_alternate_tgs(krb5_kdc_req *request, krb5_db_entry *server,
769
 
                   krb5_boolean *more, int *nprincs)
 
1032
                   krb5_boolean *more, int *nprincs)
770
1033
{
771
1034
    krb5_error_code retval;
772
1035
    krb5_principal *plist, *pl2;
782
1045
     * the principal.
783
1046
     */
784
1047
    if ((retval = krb5_walk_realm_tree(kdc_context, 
785
 
                      krb5_princ_realm(kdc_context, request->server),
786
 
                      krb5_princ_component(kdc_context, request->server, 1),
787
 
                                      &plist, KRB5_REALM_BRANCH_CHAR)))
788
 
        return;
 
1048
      krb5_princ_realm(kdc_context, request->server),
 
1049
      krb5_princ_component(kdc_context, request->server, 1),
 
1050
                      &plist, KRB5_REALM_BRANCH_CHAR)))
 
1051
        return;
789
1052
 
790
1053
    /* move to the end */
791
1054
    for (pl2 = plist; *pl2; pl2++);
793
1056
    /* the first entry in this array is for krbtgt/local@local, so we
794
1057
       ignore it */
795
1058
    while (--pl2 > plist) {
796
 
        *nprincs = 1;
797
 
        tmp = *krb5_princ_realm(kdc_context, *pl2);
798
 
        krb5_princ_set_realm(kdc_context, *pl2, 
799
 
                             krb5_princ_realm(kdc_context, tgs_server));
800
 
        retval = krb5_db_get_principal(kdc_context, *pl2, server, nprincs, more);
801
 
        krb5_princ_set_realm(kdc_context, *pl2, &tmp);
802
 
        if (retval) {
803
 
            *nprincs = 0;
804
 
            *more = FALSE;
805
 
            krb5_free_realm_tree(kdc_context, plist);
806
 
            return;
807
 
        }
808
 
        if (*more) {
809
 
            krb5_db_free_principal(kdc_context, server, *nprincs);
810
 
            continue;
811
 
        } else if (*nprincs == 1) {
812
 
            /* Found it! */
813
 
            krb5_principal tmpprinc;
814
 
            char *sname;
815
 
 
816
 
            tmp = *krb5_princ_realm(kdc_context, *pl2);
817
 
            krb5_princ_set_realm(kdc_context, *pl2, 
818
 
                                 krb5_princ_realm(kdc_context, tgs_server));
819
 
            if ((retval = krb5_copy_principal(kdc_context, *pl2, &tmpprinc))) {
820
 
                krb5_db_free_principal(kdc_context, server, *nprincs);
821
 
                krb5_princ_set_realm(kdc_context, *pl2, &tmp);
822
 
                continue;
823
 
            }
824
 
            krb5_princ_set_realm(kdc_context, *pl2, &tmp);
825
 
 
826
 
            krb5_free_principal(kdc_context, request->server);
827
 
            request->server = tmpprinc;
828
 
            if (krb5_unparse_name(kdc_context, request->server, &sname)) {
829
 
                krb5_klog_syslog(LOG_INFO,
830
 
                       "TGS_REQ: issuing alternate <un-unparseable> TGT");
831
 
            } else {
832
 
                limit_string(sname);
833
 
                krb5_klog_syslog(LOG_INFO,
834
 
                       "TGS_REQ: issuing TGT %s", sname);
835
 
                free(sname);
836
 
            }
837
 
            return;
838
 
        }
839
 
        krb5_db_free_principal(kdc_context, server, *nprincs);
840
 
        continue;
 
1059
        *nprincs = 1;
 
1060
        tmp = *krb5_princ_realm(kdc_context, *pl2);
 
1061
        krb5_princ_set_realm(kdc_context, *pl2, 
 
1062
             krb5_princ_realm(kdc_context, tgs_server));
 
1063
        retval = get_principal(kdc_context, *pl2, server, nprincs, more);
 
1064
        krb5_princ_set_realm(kdc_context, *pl2, &tmp);
 
1065
        if (retval) {
 
1066
            *nprincs = 0;
 
1067
            *more = FALSE;
 
1068
            krb5_free_realm_tree(kdc_context, plist);
 
1069
            return;
 
1070
        }
 
1071
        if (*more) {
 
1072
            krb5_db_free_principal(kdc_context, server, *nprincs);
 
1073
            continue;
 
1074
        } else if (*nprincs == 1) {
 
1075
            /* Found it! */
 
1076
            krb5_principal tmpprinc;
 
1077
 
 
1078
            tmp = *krb5_princ_realm(kdc_context, *pl2);
 
1079
            krb5_princ_set_realm(kdc_context, *pl2, 
 
1080
                 krb5_princ_realm(kdc_context, tgs_server));
 
1081
            if ((retval = krb5_copy_principal(kdc_context, *pl2, &tmpprinc))) {
 
1082
                                              krb5_db_free_principal(kdc_context, server, *nprincs);
 
1083
                                              krb5_princ_set_realm(kdc_context, *pl2, &tmp);
 
1084
                                              continue;
 
1085
            }
 
1086
            krb5_princ_set_realm(kdc_context, *pl2, &tmp);
 
1087
 
 
1088
            krb5_free_principal(kdc_context, request->server);
 
1089
            request->server = tmpprinc;
 
1090
            log_tgs_alt_tgt(request->server);
 
1091
            krb5_free_realm_tree(kdc_context, plist);
 
1092
            return;
 
1093
        }
 
1094
        krb5_db_free_principal(kdc_context, server, *nprincs);
 
1095
        continue;
841
1096
    }
842
1097
 
843
1098
    *nprincs = 0;
845
1100
    krb5_free_realm_tree(kdc_context, plist);
846
1101
    return;
847
1102
}
 
1103
 
 
1104
static krb5_int32
 
1105
prep_reprocess_req(krb5_kdc_req *request, krb5_principal *krbtgt_princ) 
 
1106
{
 
1107
    krb5_error_code retval = KRB5KRB_AP_ERR_BADMATCH;
 
1108
    size_t len = 0;
 
1109
    char **realms, **cpp, *temp_buf=NULL;
 
1110
    krb5_data *comp1 = NULL, *comp2 = NULL; 
 
1111
    char *comp1_str = NULL; 
 
1112
 
 
1113
    /* By now we know that server principal name is unknown.
 
1114
     * If CANONICALIZE flag is set in the request                                 
 
1115
     * If req is not U2U authn. req                                               
 
1116
     * the requested server princ. has exactly two components                     
 
1117
     * either 
 
1118
     *      the name type is NT-SRV-HST                                           
 
1119
     *      or name type is NT-UNKNOWN and 
 
1120
     *         the 1st component is listed in conf file under host_based_services 
 
1121
     * the 1st component is not in a list in conf under "no_host_referral"        
 
1122
     * the 2d component looks like fully-qualified domain name (FQDN)              
 
1123
     * If all of these conditions are satisfied - try mapping the FQDN and 
 
1124
     * re-process the request as if client had asked for cross-realm TGT.
 
1125
     */
 
1126
    if (isflagset(request->kdc_options, KDC_OPT_CANONICALIZE) &&   
 
1127
        !isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY) && 
 
1128
        krb5_princ_size(kdc_context, request->server) == 2) {             
 
1129
 
 
1130
        comp1 = krb5_princ_component(kdc_context, request->server, 0);
 
1131
        comp2 = krb5_princ_component(kdc_context, request->server, 1);
 
1132
 
 
1133
        comp1_str = calloc(1,comp1->length+1);
 
1134
        if (!comp1_str) {
 
1135
            retval = ENOMEM; 
 
1136
            goto cleanup; 
 
1137
         }
 
1138
        strlcpy(comp1_str,comp1->data,comp1->length+1);
 
1139
 
 
1140
        if ((krb5_princ_type(kdc_context, request->server) == KRB5_NT_SRV_HST || 
 
1141
            (krb5_princ_type(kdc_context, request->server) == KRB5_NT_UNKNOWN &&   
 
1142
            kdc_active_realm->realm_host_based_services != NULL &&
 
1143
            (krb5_match_config_pattern(kdc_active_realm->realm_host_based_services, comp1_str) == TRUE ||
 
1144
             krb5_match_config_pattern(kdc_active_realm->realm_host_based_services, KRB5_CONF_ASTERISK) == TRUE))) &&
 
1145
            (kdc_active_realm->realm_no_host_referral == NULL || 
 
1146
            (krb5_match_config_pattern(kdc_active_realm->realm_no_host_referral, KRB5_CONF_ASTERISK) == FALSE &&
 
1147
             krb5_match_config_pattern(kdc_active_realm->realm_no_host_referral, comp1_str) == FALSE))) { 
 
1148
 
 
1149
            for (len=0; len < comp2->length; len++) {     
 
1150
                 if (comp2->data[len] == '.') break;
 
1151
            }
 
1152
            if (len == comp2->length)    
 
1153
                goto cleanup; 
 
1154
            temp_buf = calloc(1, comp2->length+1);
 
1155
            if (!temp_buf){
 
1156
                retval = ENOMEM; 
 
1157
                goto cleanup;
 
1158
            }
 
1159
            strlcpy(temp_buf, comp2->data,comp2->length+1);
 
1160
            retval = krb5int_get_domain_realm_mapping(kdc_context, temp_buf, &realms);
 
1161
            free(temp_buf);
 
1162
            if (retval) {
 
1163
                /* no match found */
 
1164
                kdc_err(kdc_context, retval, 0);
 
1165
                goto cleanup;
 
1166
            }
 
1167
            if (realms == 0) {
 
1168
                retval = KRB5KRB_AP_ERR_BADMATCH;
 
1169
                goto cleanup;
 
1170
            }
 
1171
            if (realms[0] == 0) {
 
1172
                free(realms);
 
1173
                retval = KRB5KRB_AP_ERR_BADMATCH;
 
1174
                goto cleanup;
 
1175
            }
 
1176
            /* Modify request. 
 
1177
             * Construct cross-realm tgt :  krbtgt/REMOTE_REALM@LOCAL_REALM 
 
1178
             * and use it as a principal in this req. 
 
1179
             */
 
1180
            retval = krb5_build_principal(kdc_context, krbtgt_princ, 
 
1181
                                          (*request->server).realm.length, 
 
1182
                                          (*request->server).realm.data, 
 
1183
                                          "krbtgt", realms[0], (char *)0);
 
1184
            for (cpp = realms; *cpp; cpp++)  
 
1185
                   free(*cpp);
 
1186
        }
 
1187
    }
 
1188
cleanup:
 
1189
    free(comp1_str);
 
1190
    return retval;
 
1191
}
 
1192
 
 
1193