~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/kdc/kaserver.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
 
3
 * (Royal Institute of Technology, Stockholm, Sweden).
 
4
 * All rights reserved.
 
5
 *
 
6
 * Redistribution and use in source and binary forms, with or without
 
7
 * modification, are permitted provided that the following conditions
 
8
 * are met:
 
9
 *
 
10
 * 1. Redistributions of source code must retain the above copyright
 
11
 *    notice, this list of conditions and the following disclaimer.
 
12
 *
 
13
 * 2. Redistributions in binary form must reproduce the above copyright
 
14
 *    notice, this list of conditions and the following disclaimer in the
 
15
 *    documentation and/or other materials provided with the distribution.
 
16
 *
 
17
 * 3. Neither the name of the Institute nor the names of its contributors
 
18
 *    may be used to endorse or promote products derived from this software
 
19
 *    without specific prior written permission.
 
20
 *
 
21
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 
22
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
23
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
24
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 
25
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
26
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
27
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
28
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
29
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
30
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
31
 * SUCH DAMAGE.
 
32
 */
 
33
 
 
34
#include "kdc_locl.h"
 
35
 
 
36
RCSID("$Id$");
 
37
 
 
38
#include <krb5-v4compat.h>
 
39
#include <rx.h>
 
40
 
 
41
#define KA_AUTHENTICATION_SERVICE 731
 
42
#define KA_TICKET_GRANTING_SERVICE 732
 
43
#define KA_MAINTENANCE_SERVICE 733
 
44
 
 
45
#define AUTHENTICATE_OLD         1
 
46
#define CHANGEPASSWORD           2
 
47
#define GETTICKET_OLD            3
 
48
#define SETPASSWORD              4
 
49
#define SETFIELDS                5
 
50
#define CREATEUSER               6
 
51
#define DELETEUSER               7
 
52
#define GETENTRY                 8
 
53
#define LISTENTRY                9
 
54
#define GETSTATS                10
 
55
#define DEBUG                   11
 
56
#define GETPASSWORD             12
 
57
#define GETRANDOMKEY            13
 
58
#define AUTHENTICATE            21
 
59
#define AUTHENTICATE_V2         22
 
60
#define GETTICKET               23
 
61
 
 
62
/* XXX - Where do we get these? */
 
63
 
 
64
#define RXGEN_OPCODE (-455)
 
65
 
 
66
#define KADATABASEINCONSISTENT                   (180480L)
 
67
#define KAEXIST                                  (180481L)
 
68
#define KAIO                                     (180482L)
 
69
#define KACREATEFAIL                             (180483L)
 
70
#define KANOENT                                  (180484L)
 
71
#define KAEMPTY                                  (180485L)
 
72
#define KABADNAME                                (180486L)
 
73
#define KABADINDEX                               (180487L)
 
74
#define KANOAUTH                                 (180488L)
 
75
#define KAANSWERTOOLONG                          (180489L)
 
76
#define KABADREQUEST                             (180490L)
 
77
#define KAOLDINTERFACE                           (180491L)
 
78
#define KABADARGUMENT                            (180492L)
 
79
#define KABADCMD                                 (180493L)
 
80
#define KANOKEYS                                 (180494L)
 
81
#define KAREADPW                                 (180495L)
 
82
#define KABADKEY                                 (180496L)
 
83
#define KAUBIKINIT                               (180497L)
 
84
#define KAUBIKCALL                               (180498L)
 
85
#define KABADPROTOCOL                            (180499L)
 
86
#define KANOCELLS                                (180500L)
 
87
#define KANOCELL                                 (180501L)
 
88
#define KATOOMANYUBIKS                           (180502L)
 
89
#define KATOOMANYKEYS                            (180503L)
 
90
#define KABADTICKET                              (180504L)
 
91
#define KAUNKNOWNKEY                             (180505L)
 
92
#define KAKEYCACHEINVALID                        (180506L)
 
93
#define KABADSERVER                              (180507L)
 
94
#define KABADUSER                                (180508L)
 
95
#define KABADCPW                                 (180509L)
 
96
#define KABADCREATE                              (180510L)
 
97
#define KANOTICKET                               (180511L)
 
98
#define KAASSOCUSER                              (180512L)
 
99
#define KANOTSPECIAL                             (180513L)
 
100
#define KACLOCKSKEW                              (180514L)
 
101
#define KANORECURSE                              (180515L)
 
102
#define KARXFAIL                                 (180516L)
 
103
#define KANULLPASSWORD                           (180517L)
 
104
#define KAINTERNALERROR                          (180518L)
 
105
#define KAPWEXPIRED                              (180519L)
 
106
#define KAREUSED                                 (180520L)
 
107
#define KATOOSOON                                (180521L)
 
108
#define KALOCKED                                 (180522L)
 
109
 
 
110
 
 
111
static krb5_error_code
 
112
decode_rx_header (krb5_storage *sp,
 
113
                  struct rx_header *h)
 
114
{
 
115
    krb5_error_code ret;
 
116
 
 
117
    ret = krb5_ret_uint32(sp, &h->epoch);
 
118
    if (ret) return ret;
 
119
    ret = krb5_ret_uint32(sp, &h->connid);
 
120
    if (ret) return ret;
 
121
    ret = krb5_ret_uint32(sp, &h->callid);
 
122
    if (ret) return ret;
 
123
    ret = krb5_ret_uint32(sp, &h->seqno);
 
124
    if (ret) return ret;
 
125
    ret = krb5_ret_uint32(sp, &h->serialno);
 
126
    if (ret) return ret;
 
127
    ret = krb5_ret_uint8(sp,  &h->type);
 
128
    if (ret) return ret;
 
129
    ret = krb5_ret_uint8(sp,  &h->flags);
 
130
    if (ret) return ret;
 
131
    ret = krb5_ret_uint8(sp,  &h->status);
 
132
    if (ret) return ret;
 
133
    ret = krb5_ret_uint8(sp,  &h->secindex);
 
134
    if (ret) return ret;
 
135
    ret = krb5_ret_uint16(sp, &h->reserved);
 
136
    if (ret) return ret;
 
137
    ret = krb5_ret_uint16(sp, &h->serviceid);
 
138
    if (ret) return ret;
 
139
 
 
140
    return 0;
 
141
}
 
142
 
 
143
static krb5_error_code
 
144
encode_rx_header (struct rx_header *h,
 
145
                  krb5_storage *sp)
 
146
{
 
147
    krb5_error_code ret;
 
148
 
 
149
    ret = krb5_store_uint32(sp, h->epoch);
 
150
    if (ret) return ret;
 
151
    ret = krb5_store_uint32(sp, h->connid);
 
152
    if (ret) return ret;
 
153
    ret = krb5_store_uint32(sp, h->callid);
 
154
    if (ret) return ret;
 
155
    ret = krb5_store_uint32(sp, h->seqno);
 
156
    if (ret) return ret;
 
157
    ret = krb5_store_uint32(sp, h->serialno);
 
158
    if (ret) return ret;
 
159
    ret = krb5_store_uint8(sp,  h->type);
 
160
    if (ret) return ret;
 
161
    ret = krb5_store_uint8(sp,  h->flags);
 
162
    if (ret) return ret;
 
163
    ret = krb5_store_uint8(sp,  h->status);
 
164
    if (ret) return ret;
 
165
    ret = krb5_store_uint8(sp,  h->secindex);
 
166
    if (ret) return ret;
 
167
    ret = krb5_store_uint16(sp, h->reserved);
 
168
    if (ret) return ret;
 
169
    ret = krb5_store_uint16(sp, h->serviceid);
 
170
    if (ret) return ret;
 
171
 
 
172
    return 0;
 
173
}
 
174
 
 
175
static void
 
176
init_reply_header (struct rx_header *hdr,
 
177
                   struct rx_header *reply_hdr,
 
178
                   u_char type,
 
179
                   u_char flags)
 
180
{
 
181
    reply_hdr->epoch     = hdr->epoch;
 
182
    reply_hdr->connid    = hdr->connid;
 
183
    reply_hdr->callid    = hdr->callid;
 
184
    reply_hdr->seqno     = 1;
 
185
    reply_hdr->serialno  = 1;
 
186
    reply_hdr->type      = type;
 
187
    reply_hdr->flags     = flags;
 
188
    reply_hdr->status    = 0;
 
189
    reply_hdr->secindex  = 0;
 
190
    reply_hdr->reserved  = 0;
 
191
    reply_hdr->serviceid = hdr->serviceid;
 
192
}
 
193
 
 
194
/*
 
195
 * Create an error `reply´ using for the packet `hdr' with the error
 
196
 * `error´ code.
 
197
 */
 
198
static void
 
199
make_error_reply (struct rx_header *hdr,
 
200
                  uint32_t error,
 
201
                  krb5_data *reply)
 
202
 
 
203
{
 
204
    struct rx_header reply_hdr;
 
205
    krb5_error_code ret;
 
206
    krb5_storage *sp;
 
207
 
 
208
    init_reply_header (hdr, &reply_hdr, HT_ABORT, HF_LAST);
 
209
    sp = krb5_storage_emem();
 
210
    if (sp == NULL)
 
211
        return;
 
212
    ret = encode_rx_header (&reply_hdr, sp);
 
213
    if (ret)
 
214
        return;
 
215
    krb5_store_int32(sp, error);
 
216
    krb5_storage_to_data (sp, reply);
 
217
    krb5_storage_free (sp);
 
218
}
 
219
 
 
220
static krb5_error_code
 
221
krb5_ret_xdr_data(krb5_storage *sp,
 
222
                  krb5_data *data)
 
223
{
 
224
    int ret;
 
225
    int size;
 
226
    ret = krb5_ret_int32(sp, &size);
 
227
    if(ret)
 
228
        return ret;
 
229
    if(size < 0)
 
230
        return ERANGE;
 
231
    data->length = size;
 
232
    if (size) {
 
233
        u_char foo[4];
 
234
        size_t pad = (4 - size % 4) % 4;
 
235
 
 
236
        data->data = malloc(size);
 
237
        if (data->data == NULL)
 
238
            return ENOMEM;
 
239
        ret = krb5_storage_read(sp, data->data, size);
 
240
        if(ret != size)
 
241
            return (ret < 0)? errno : KRB5_CC_END;
 
242
        if (pad) {
 
243
            ret = krb5_storage_read(sp, foo, pad);
 
244
            if (ret != pad)
 
245
                return (ret < 0)? errno : KRB5_CC_END;
 
246
        }
 
247
    } else
 
248
        data->data = NULL;
 
249
    return 0;
 
250
}
 
251
 
 
252
static krb5_error_code
 
253
krb5_store_xdr_data(krb5_storage *sp,
 
254
                    krb5_data data)
 
255
{
 
256
    u_char zero[4] = {0, 0, 0, 0};
 
257
    int ret;
 
258
    size_t pad;
 
259
 
 
260
    ret = krb5_store_int32(sp, data.length);
 
261
    if(ret < 0)
 
262
        return ret;
 
263
    ret = krb5_storage_write(sp, data.data, data.length);
 
264
    if(ret != data.length){
 
265
        if(ret < 0)
 
266
            return errno;
 
267
        return KRB5_CC_END;
 
268
    }
 
269
    pad = (4 - data.length % 4) % 4;
 
270
    if (pad) {
 
271
        ret = krb5_storage_write(sp, zero, pad);
 
272
        if (ret != pad) {
 
273
            if (ret < 0)
 
274
                return errno;
 
275
            return KRB5_CC_END;
 
276
        }
 
277
    }
 
278
    return 0;
 
279
}
 
280
 
 
281
 
 
282
static krb5_error_code
 
283
create_reply_ticket (krb5_context context,
 
284
                     struct rx_header *hdr,
 
285
                     Key *skey,
 
286
                     char *name, char *instance, char *realm,
 
287
                     struct sockaddr_in *addr,
 
288
                     int life,
 
289
                     int kvno,
 
290
                     int32_t max_seq_len,
 
291
                     const char *sname, const char *sinstance,
 
292
                     uint32_t challenge,
 
293
                     const char *label,
 
294
                     krb5_keyblock *key,
 
295
                     krb5_data *reply)
 
296
{
 
297
    krb5_error_code ret;
 
298
    krb5_data ticket;
 
299
    krb5_keyblock session;
 
300
    krb5_storage *sp;
 
301
    krb5_data enc_data;
 
302
    struct rx_header reply_hdr;
 
303
    char zero[8];
 
304
    size_t pad;
 
305
    unsigned fyrtiosjuelva;
 
306
 
 
307
    /* create the ticket */
 
308
 
 
309
    krb5_generate_random_keyblock(context, ETYPE_DES_PCBC_NONE, &session);
 
310
 
 
311
    _krb5_krb_create_ticket(context,
 
312
                            0,
 
313
                            name,
 
314
                            instance,
 
315
                            realm,
 
316
                            addr->sin_addr.s_addr,
 
317
                            &session,
 
318
                            life,
 
319
                            kdc_time,
 
320
                            sname,
 
321
                            sinstance,
 
322
                            &skey->key,
 
323
                            &ticket);
 
324
 
 
325
    /* create the encrypted part of the reply */
 
326
    sp = krb5_storage_emem ();
 
327
    krb5_generate_random_block(&fyrtiosjuelva, sizeof(fyrtiosjuelva));
 
328
    fyrtiosjuelva &= 0xffffffff;
 
329
    krb5_store_int32 (sp, fyrtiosjuelva);
 
330
    krb5_store_int32 (sp, challenge);
 
331
    krb5_storage_write  (sp, session.keyvalue.data, 8);
 
332
    krb5_free_keyblock_contents(context, &session);
 
333
    krb5_store_int32 (sp, kdc_time);
 
334
    krb5_store_int32 (sp, kdc_time + _krb5_krb_life_to_time (0, life));
 
335
    krb5_store_int32 (sp, kvno);
 
336
    krb5_store_int32 (sp, ticket.length);
 
337
    krb5_store_stringz (sp, name);
 
338
    krb5_store_stringz (sp, instance);
 
339
#if 1 /* XXX - Why shouldn't the realm go here? */
 
340
    krb5_store_stringz (sp, "");
 
341
#else
 
342
    krb5_store_stringz (sp, realm);
 
343
#endif
 
344
    krb5_store_stringz (sp, sname);
 
345
    krb5_store_stringz (sp, sinstance);
 
346
    krb5_storage_write (sp, ticket.data, ticket.length);
 
347
    krb5_storage_write (sp, label, strlen(label));
 
348
 
 
349
    /* pad to DES block */
 
350
    memset (zero, 0, sizeof(zero));
 
351
    pad = (8 - krb5_storage_seek (sp, 0, SEEK_CUR) % 8) % 8;
 
352
    krb5_storage_write (sp, zero, pad);
 
353
 
 
354
    krb5_storage_to_data (sp, &enc_data);
 
355
    krb5_storage_free (sp);
 
356
 
 
357
    if (enc_data.length > max_seq_len) {
 
358
        krb5_data_free (&enc_data);
 
359
        make_error_reply (hdr, KAANSWERTOOLONG, reply);
 
360
        return 0;
 
361
    }
 
362
 
 
363
    /* encrypt it */
 
364
    {
 
365
        DES_key_schedule schedule;
 
366
        DES_cblock deskey;
 
367
        
 
368
        memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
 
369
        DES_set_key_unchecked (&deskey, &schedule);
 
370
        DES_pcbc_encrypt (enc_data.data,
 
371
                          enc_data.data,
 
372
                          enc_data.length,
 
373
                          &schedule,
 
374
                          &deskey,
 
375
                          DES_ENCRYPT);
 
376
        memset (&schedule, 0, sizeof(schedule));
 
377
        memset (&deskey, 0, sizeof(deskey));
 
378
    }
 
379
 
 
380
    /* create the reply packet */
 
381
    init_reply_header (hdr, &reply_hdr, HT_DATA, HF_LAST);
 
382
    sp = krb5_storage_emem ();
 
383
    ret = encode_rx_header (&reply_hdr, sp);
 
384
    krb5_store_int32 (sp, max_seq_len);
 
385
    krb5_store_xdr_data (sp, enc_data);
 
386
    krb5_data_free (&enc_data);
 
387
    krb5_storage_to_data (sp, reply);
 
388
    krb5_storage_free (sp);
 
389
    return 0;
 
390
}
 
391
 
 
392
static krb5_error_code
 
393
unparse_auth_args (krb5_storage *sp,
 
394
                   char **name,
 
395
                   char **instance,
 
396
                   time_t *start_time,
 
397
                   time_t *end_time,
 
398
                   krb5_data *request,
 
399
                   int32_t *max_seq_len)
 
400
{
 
401
    krb5_data data;
 
402
    int32_t tmp;
 
403
 
 
404
    krb5_ret_xdr_data (sp, &data);
 
405
    *name = malloc(data.length + 1);
 
406
    if (*name == NULL)
 
407
        return ENOMEM;
 
408
    memcpy (*name, data.data, data.length);
 
409
    (*name)[data.length] = '\0';
 
410
    krb5_data_free (&data);
 
411
 
 
412
    krb5_ret_xdr_data (sp, &data);
 
413
    *instance = malloc(data.length + 1);
 
414
    if (*instance == NULL) {
 
415
        free (*name);
 
416
        return ENOMEM;
 
417
    }
 
418
    memcpy (*instance, data.data, data.length);
 
419
    (*instance)[data.length] = '\0';
 
420
    krb5_data_free (&data);
 
421
 
 
422
    krb5_ret_int32 (sp, &tmp);
 
423
    *start_time = tmp;
 
424
    krb5_ret_int32 (sp, &tmp);
 
425
    *end_time = tmp;
 
426
    krb5_ret_xdr_data (sp, request);
 
427
    krb5_ret_int32 (sp, max_seq_len);
 
428
    /* ignore the rest */
 
429
    return 0;
 
430
}
 
431
 
 
432
static void
 
433
do_authenticate (krb5_context context,
 
434
                 krb5_kdc_configuration *config,
 
435
                 struct rx_header *hdr,
 
436
                 krb5_storage *sp,
 
437
                 struct sockaddr_in *addr,
 
438
                 const char *from,
 
439
                 krb5_data *reply)
 
440
{
 
441
    krb5_error_code ret;
 
442
    char *name = NULL;
 
443
    char *instance = NULL;
 
444
    time_t start_time;
 
445
    time_t end_time;
 
446
    krb5_data request;
 
447
    int32_t max_seq_len;
 
448
    hdb_entry_ex *client_entry = NULL;
 
449
    hdb_entry_ex *server_entry = NULL;
 
450
    Key *ckey = NULL;
 
451
    Key *skey = NULL;
 
452
    krb5_storage *reply_sp;
 
453
    time_t max_life;
 
454
    uint8_t life;
 
455
    int32_t chal;
 
456
    char client_name[256];
 
457
    char server_name[256];
 
458
        
 
459
    krb5_data_zero (&request);
 
460
 
 
461
    ret = unparse_auth_args (sp, &name, &instance, &start_time, &end_time,
 
462
                             &request, &max_seq_len);
 
463
    if (ret != 0 || request.length < 8) {
 
464
        make_error_reply (hdr, KABADREQUEST, reply);
 
465
        goto out;
 
466
    }
 
467
 
 
468
    snprintf (client_name, sizeof(client_name), "%s.%s@%s",
 
469
              name, instance, config->v4_realm);
 
470
    snprintf (server_name, sizeof(server_name), "%s.%s@%s",
 
471
              "krbtgt", config->v4_realm, config->v4_realm);
 
472
 
 
473
    kdc_log(context, config, 0, "AS-REQ (kaserver) %s from %s for %s",
 
474
            client_name, from, server_name);
 
475
 
 
476
    ret = _kdc_db_fetch4 (context, config, name, instance,
 
477
                          config->v4_realm, HDB_F_GET_CLIENT,
 
478
                          &client_entry);
 
479
    if (ret) {
 
480
        kdc_log(context, config, 0, "Client not found in database: %s: %s",
 
481
                client_name, krb5_get_err_text(context, ret));
 
482
        make_error_reply (hdr, KANOENT, reply);
 
483
        goto out;
 
484
    }
 
485
 
 
486
    ret = _kdc_db_fetch4 (context, config, "krbtgt",
 
487
                          config->v4_realm, config->v4_realm,
 
488
                          HDB_F_GET_KRBTGT, &server_entry);
 
489
    if (ret) {
 
490
        kdc_log(context, config, 0, "Server not found in database: %s: %s",
 
491
                server_name, krb5_get_err_text(context, ret));
 
492
        make_error_reply (hdr, KANOENT, reply);
 
493
        goto out;
 
494
    }
 
495
 
 
496
    ret = _kdc_check_flags (context, config,
 
497
                            client_entry, client_name,
 
498
                            server_entry, server_name,
 
499
                            TRUE);
 
500
    if (ret) {
 
501
        make_error_reply (hdr, KAPWEXPIRED, reply);
 
502
        goto out;
 
503
    }
 
504
 
 
505
    /* find a DES key */
 
506
    ret = _kdc_get_des_key(context, client_entry, FALSE, TRUE, &ckey);
 
507
    if(ret){
 
508
        kdc_log(context, config, 0, "no suitable DES key for client");
 
509
        make_error_reply (hdr, KANOKEYS, reply);
 
510
        goto out;
 
511
    }
 
512
 
 
513
    /* find a DES key */
 
514
    ret = _kdc_get_des_key(context, server_entry, TRUE, TRUE, &skey);
 
515
    if(ret){
 
516
        kdc_log(context, config, 0, "no suitable DES key for server");
 
517
        make_error_reply (hdr, KANOKEYS, reply);
 
518
        goto out;
 
519
    }
 
520
 
 
521
    {
 
522
        DES_cblock key;
 
523
        DES_key_schedule schedule;
 
524
        
 
525
        /* try to decode the `request' */
 
526
        memcpy (&key, ckey->key.keyvalue.data, sizeof(key));
 
527
        DES_set_key_unchecked (&key, &schedule);
 
528
        DES_pcbc_encrypt (request.data,
 
529
                          request.data,
 
530
                          request.length,
 
531
                          &schedule,
 
532
                          &key,
 
533
                          DES_DECRYPT);
 
534
        memset (&schedule, 0, sizeof(schedule));
 
535
        memset (&key, 0, sizeof(key));
 
536
    }
 
537
 
 
538
    /* check for the magic label */
 
539
    if (memcmp ((char *)request.data + 4, "gTGS", 4) != 0) {
 
540
        kdc_log(context, config, 0, "preauth failed for %s", client_name);
 
541
        make_error_reply (hdr, KABADREQUEST, reply);
 
542
        goto out;
 
543
    }
 
544
 
 
545
    reply_sp = krb5_storage_from_mem (request.data, 4);
 
546
    krb5_ret_int32 (reply_sp, &chal);
 
547
    krb5_storage_free (reply_sp);
 
548
 
 
549
    if (abs(chal - kdc_time) > context->max_skew) {
 
550
        make_error_reply (hdr, KACLOCKSKEW, reply);
 
551
        goto out;
 
552
    }
 
553
 
 
554
    /* life */
 
555
    max_life = end_time - kdc_time;
 
556
    /* end_time - kdc_time can sometimes be non-positive due to slight
 
557
       time skew between client and server. Let's make sure it is postive */
 
558
    if(max_life < 1)
 
559
        max_life = 1;
 
560
    if (client_entry->entry.max_life)
 
561
        max_life = min(max_life, *client_entry->entry.max_life);
 
562
    if (server_entry->entry.max_life)
 
563
        max_life = min(max_life, *server_entry->entry.max_life);
 
564
 
 
565
    life = krb_time_to_life(kdc_time, kdc_time + max_life);
 
566
 
 
567
    create_reply_ticket (context,
 
568
                         hdr, skey,
 
569
                         name, instance, config->v4_realm,
 
570
                         addr, life, server_entry->entry.kvno,
 
571
                         max_seq_len,
 
572
                         "krbtgt", config->v4_realm,
 
573
                         chal + 1, "tgsT",
 
574
                         &ckey->key, reply);
 
575
 
 
576
 out:
 
577
    if (request.length) {
 
578
        memset (request.data, 0, request.length);
 
579
        krb5_data_free (&request);
 
580
    }
 
581
    if (name)
 
582
        free (name);
 
583
    if (instance)
 
584
        free (instance);
 
585
    if (client_entry)
 
586
        _kdc_free_ent (context, client_entry);
 
587
    if (server_entry)
 
588
        _kdc_free_ent (context, server_entry);
 
589
}
 
590
 
 
591
static krb5_error_code
 
592
unparse_getticket_args (krb5_storage *sp,
 
593
                        int *kvno,
 
594
                        char **auth_domain,
 
595
                        krb5_data *ticket,
 
596
                        char **name,
 
597
                        char **instance,
 
598
                        krb5_data *times,
 
599
                        int32_t *max_seq_len)
 
600
{
 
601
    krb5_data data;
 
602
    int32_t tmp;
 
603
 
 
604
    krb5_ret_int32 (sp, &tmp);
 
605
    *kvno = tmp;
 
606
 
 
607
    krb5_ret_xdr_data (sp, &data);
 
608
    *auth_domain = malloc(data.length + 1);
 
609
    if (*auth_domain == NULL)
 
610
        return ENOMEM;
 
611
    memcpy (*auth_domain, data.data, data.length);
 
612
    (*auth_domain)[data.length] = '\0';
 
613
    krb5_data_free (&data);
 
614
 
 
615
    krb5_ret_xdr_data (sp, ticket);
 
616
 
 
617
    krb5_ret_xdr_data (sp, &data);
 
618
    *name = malloc(data.length + 1);
 
619
    if (*name == NULL) {
 
620
        free (*auth_domain);
 
621
        return ENOMEM;
 
622
    }
 
623
    memcpy (*name, data.data, data.length);
 
624
    (*name)[data.length] = '\0';
 
625
    krb5_data_free (&data);
 
626
 
 
627
    krb5_ret_xdr_data (sp, &data);
 
628
    *instance = malloc(data.length + 1);
 
629
    if (*instance == NULL) {
 
630
        free (*auth_domain);
 
631
        free (*name);
 
632
        return ENOMEM;
 
633
    }
 
634
    memcpy (*instance, data.data, data.length);
 
635
    (*instance)[data.length] = '\0';
 
636
    krb5_data_free (&data);
 
637
 
 
638
    krb5_ret_xdr_data (sp, times);
 
639
 
 
640
    krb5_ret_int32 (sp, max_seq_len);
 
641
    /* ignore the rest */
 
642
    return 0;
 
643
}
 
644
 
 
645
static void
 
646
do_getticket (krb5_context context,
 
647
              krb5_kdc_configuration *config,
 
648
              struct rx_header *hdr,
 
649
              krb5_storage *sp,
 
650
              struct sockaddr_in *addr,
 
651
              const char *from,
 
652
              krb5_data *reply)
 
653
{
 
654
    krb5_error_code ret;
 
655
    int kvno;
 
656
    char *auth_domain = NULL;
 
657
    krb5_data aticket;
 
658
    char *name = NULL;
 
659
    char *instance = NULL;
 
660
    krb5_data times;
 
661
    int32_t max_seq_len;
 
662
    hdb_entry_ex *server_entry = NULL;
 
663
    hdb_entry_ex *client_entry = NULL;
 
664
    hdb_entry_ex *krbtgt_entry = NULL;
 
665
    Key *kkey = NULL;
 
666
    Key *skey = NULL;
 
667
    DES_cblock key;
 
668
    DES_key_schedule schedule;
 
669
    DES_cblock session;
 
670
    time_t max_life;
 
671
    int8_t life;
 
672
    time_t start_time, end_time;
 
673
    char server_name[256];
 
674
    char client_name[256];
 
675
    struct _krb5_krb_auth_data ad;
 
676
 
 
677
    krb5_data_zero (&aticket);
 
678
    krb5_data_zero (&times);
 
679
 
 
680
    memset(&ad, 0, sizeof(ad));
 
681
 
 
682
    unparse_getticket_args (sp, &kvno, &auth_domain, &aticket,
 
683
                            &name, &instance, &times, &max_seq_len);
 
684
    if (times.length < 8) {
 
685
        make_error_reply (hdr, KABADREQUEST, reply);
 
686
        goto out;
 
687
        
 
688
    }
 
689
 
 
690
    snprintf (server_name, sizeof(server_name),
 
691
              "%s.%s@%s", name, instance, config->v4_realm);
 
692
 
 
693
    ret = _kdc_db_fetch4 (context, config, name, instance,
 
694
                          config->v4_realm, HDB_F_GET_SERVER, &server_entry);
 
695
    if (ret) {
 
696
        kdc_log(context, config, 0, "Server not found in database: %s: %s",
 
697
                server_name, krb5_get_err_text(context, ret));
 
698
        make_error_reply (hdr, KANOENT, reply);
 
699
        goto out;
 
700
    }
 
701
 
 
702
    ret = _kdc_db_fetch4 (context, config, "krbtgt",
 
703
                     config->v4_realm, config->v4_realm, HDB_F_GET_KRBTGT, &krbtgt_entry);
 
704
    if (ret) {
 
705
        kdc_log(context, config, 0,
 
706
                "Server not found in database: %s.%s@%s: %s",
 
707
                "krbtgt", config->v4_realm,  config->v4_realm,
 
708
                krb5_get_err_text(context, ret));
 
709
        make_error_reply (hdr, KANOENT, reply);
 
710
        goto out;
 
711
    }
 
712
 
 
713
    /* find a DES key */
 
714
    ret = _kdc_get_des_key(context, krbtgt_entry, TRUE, TRUE, &kkey);
 
715
    if(ret){
 
716
        kdc_log(context, config, 0, "no suitable DES key for krbtgt");
 
717
        make_error_reply (hdr, KANOKEYS, reply);
 
718
        goto out;
 
719
    }
 
720
 
 
721
    /* find a DES key */
 
722
    ret = _kdc_get_des_key(context, server_entry, TRUE, TRUE, &skey);
 
723
    if(ret){
 
724
        kdc_log(context, config, 0, "no suitable DES key for server");
 
725
        make_error_reply (hdr, KANOKEYS, reply);
 
726
        goto out;
 
727
    }
 
728
 
 
729
    /* decrypt the incoming ticket */
 
730
    memcpy (&key, kkey->key.keyvalue.data, sizeof(key));
 
731
 
 
732
    /* unpack the ticket */
 
733
    {
 
734
        char *sname = NULL;
 
735
        char *sinstance = NULL;
 
736
 
 
737
        ret = _krb5_krb_decomp_ticket(context, &aticket, &kkey->key,
 
738
                                      config->v4_realm, &sname,
 
739
                                      &sinstance, &ad);
 
740
        if (ret) {
 
741
            kdc_log(context, config, 0,
 
742
                    "kaserver: decomp failed for %s.%s with %d",
 
743
                    sname, sinstance, ret);
 
744
            make_error_reply (hdr, KABADTICKET, reply);
 
745
            goto out;
 
746
        }
 
747
 
 
748
        if (strcmp (sname, "krbtgt") != 0
 
749
            || strcmp (sinstance, config->v4_realm) != 0) {
 
750
            kdc_log(context, config, 0, "no TGT: %s.%s for %s.%s@%s",
 
751
                    sname, sinstance,
 
752
                    ad.pname, ad.pinst, ad.prealm);
 
753
            make_error_reply (hdr, KABADTICKET, reply);
 
754
            free(sname);
 
755
            free(sinstance);
 
756
            goto out;
 
757
        }
 
758
        free(sname);
 
759
        free(sinstance);
 
760
 
 
761
        if (kdc_time > _krb5_krb_life_to_time(ad.time_sec, ad.life)) {
 
762
            kdc_log(context, config, 0, "TGT expired: %s.%s@%s",
 
763
                    ad.pname, ad.pinst, ad.prealm);
 
764
            make_error_reply (hdr, KABADTICKET, reply);
 
765
            goto out;
 
766
        }
 
767
    }
 
768
 
 
769
    snprintf (client_name, sizeof(client_name),
 
770
              "%s.%s@%s", ad.pname, ad.pinst, ad.prealm);
 
771
 
 
772
    kdc_log(context, config, 0, "TGS-REQ (kaserver) %s from %s for %s",
 
773
            client_name, from, server_name);
 
774
 
 
775
    ret = _kdc_db_fetch4 (context, config,
 
776
                          ad.pname, ad.pinst, ad.prealm, HDB_F_GET_CLIENT,
 
777
                          &client_entry);
 
778
    if(ret && ret != HDB_ERR_NOENTRY) {
 
779
        kdc_log(context, config, 0,
 
780
                "Client not found in database: (krb4) %s: %s",
 
781
                client_name, krb5_get_err_text(context, ret));
 
782
        make_error_reply (hdr, KANOENT, reply);
 
783
        goto out;
 
784
    }
 
785
    if (client_entry == NULL && strcmp(ad.prealm, config->v4_realm) == 0) {
 
786
        kdc_log(context, config, 0,
 
787
                "Local client not found in database: (krb4) "
 
788
                "%s", client_name);
 
789
        make_error_reply (hdr, KANOENT, reply);
 
790
        goto out;
 
791
    }
 
792
 
 
793
    ret = _kdc_check_flags (context, config,
 
794
                            client_entry, client_name,
 
795
                            server_entry, server_name,
 
796
                            FALSE);
 
797
    if (ret) {
 
798
        make_error_reply (hdr, KAPWEXPIRED, reply);
 
799
        goto out;
 
800
    }
 
801
 
 
802
    /* decrypt the times */
 
803
    memcpy(&session, ad.session.keyvalue.data, sizeof(session));
 
804
    DES_set_key_unchecked (&session, &schedule);
 
805
    DES_ecb_encrypt (times.data,
 
806
                     times.data,
 
807
                     &schedule,
 
808
                     DES_DECRYPT);
 
809
    memset (&schedule, 0, sizeof(schedule));
 
810
    memset (&session, 0, sizeof(session));
 
811
 
 
812
    /* and extract them */
 
813
    {
 
814
        krb5_storage *tsp;
 
815
        int32_t tmp;
 
816
 
 
817
        tsp = krb5_storage_from_mem (times.data, times.length);
 
818
        krb5_ret_int32 (tsp, &tmp);
 
819
        start_time = tmp;
 
820
        krb5_ret_int32 (tsp, &tmp);
 
821
        end_time = tmp;
 
822
        krb5_storage_free (tsp);
 
823
    }
 
824
 
 
825
    /* life */
 
826
    max_life = end_time - kdc_time;
 
827
    /* end_time - kdc_time can sometimes be non-positive due to slight
 
828
       time skew between client and server. Let's make sure it is postive */
 
829
    if(max_life < 1)
 
830
        max_life = 1;
 
831
    if (krbtgt_entry->entry.max_life)
 
832
        max_life = min(max_life, *krbtgt_entry->entry.max_life);
 
833
    if (server_entry->entry.max_life)
 
834
        max_life = min(max_life, *server_entry->entry.max_life);
 
835
    /* if this is a cross realm request, the client_entry will likely
 
836
       be NULL */
 
837
    if (client_entry && client_entry->entry.max_life)
 
838
        max_life = min(max_life, *client_entry->entry.max_life);
 
839
 
 
840
    life = _krb5_krb_time_to_life(kdc_time, kdc_time + max_life);
 
841
 
 
842
    create_reply_ticket (context,
 
843
                         hdr, skey,
 
844
                         ad.pname, ad.pinst, ad.prealm,
 
845
                         addr, life, server_entry->entry.kvno,
 
846
                         max_seq_len,
 
847
                         name, instance,
 
848
                         0, "gtkt",
 
849
                         &ad.session, reply);
 
850
 
 
851
 out:
 
852
    _krb5_krb_free_auth_data(context, &ad);
 
853
    if (aticket.length) {
 
854
        memset (aticket.data, 0, aticket.length);
 
855
        krb5_data_free (&aticket);
 
856
    }
 
857
    if (times.length) {
 
858
        memset (times.data, 0, times.length);
 
859
        krb5_data_free (&times);
 
860
    }
 
861
    if (auth_domain)
 
862
        free (auth_domain);
 
863
    if (name)
 
864
        free (name);
 
865
    if (instance)
 
866
        free (instance);
 
867
    if (krbtgt_entry)
 
868
        _kdc_free_ent (context, krbtgt_entry);
 
869
    if (server_entry)
 
870
        _kdc_free_ent (context, server_entry);
 
871
}
 
872
 
 
873
krb5_error_code
 
874
_kdc_do_kaserver(krb5_context context,
 
875
                 krb5_kdc_configuration *config,
 
876
                 unsigned char *buf,
 
877
                 size_t len,
 
878
                 krb5_data *reply,
 
879
                 const char *from,
 
880
                 struct sockaddr_in *addr)
 
881
{
 
882
    krb5_error_code ret = 0;
 
883
    struct rx_header hdr;
 
884
    uint32_t op;
 
885
    krb5_storage *sp;
 
886
 
 
887
    if (len < RX_HEADER_SIZE)
 
888
        return -1;
 
889
    sp = krb5_storage_from_mem (buf, len);
 
890
 
 
891
    ret = decode_rx_header (sp, &hdr);
 
892
    if (ret)
 
893
        goto out;
 
894
    buf += RX_HEADER_SIZE;
 
895
    len -= RX_HEADER_SIZE;
 
896
 
 
897
    switch (hdr.type) {
 
898
    case HT_DATA :
 
899
        break;
 
900
    case HT_ACK :
 
901
    case HT_BUSY :
 
902
    case HT_ABORT :
 
903
    case HT_ACKALL :
 
904
    case HT_CHAL :
 
905
    case HT_RESP :
 
906
    case HT_DEBUG :
 
907
    default:
 
908
        /* drop */
 
909
        goto out;
 
910
    }
 
911
 
 
912
 
 
913
    if (hdr.serviceid != KA_AUTHENTICATION_SERVICE
 
914
        && hdr.serviceid != KA_TICKET_GRANTING_SERVICE) {
 
915
        ret = -1;
 
916
        goto out;
 
917
    }
 
918
 
 
919
    ret = krb5_ret_uint32(sp, &op);
 
920
    if (ret)
 
921
        goto out;
 
922
    switch (op) {
 
923
    case AUTHENTICATE :
 
924
    case AUTHENTICATE_V2 :
 
925
        do_authenticate (context, config, &hdr, sp, addr, from, reply);
 
926
        break;
 
927
    case GETTICKET :
 
928
        do_getticket (context, config, &hdr, sp, addr, from, reply);
 
929
        break;
 
930
    case AUTHENTICATE_OLD :
 
931
    case CHANGEPASSWORD :
 
932
    case GETTICKET_OLD :
 
933
    case SETPASSWORD :
 
934
    case SETFIELDS :
 
935
    case CREATEUSER :
 
936
    case DELETEUSER :
 
937
    case GETENTRY :
 
938
    case LISTENTRY :
 
939
    case GETSTATS :
 
940
    case DEBUG :
 
941
    case GETPASSWORD :
 
942
    case GETRANDOMKEY :
 
943
    default :
 
944
        make_error_reply (&hdr, RXGEN_OPCODE, reply);
 
945
        break;
 
946
    }
 
947
 
 
948
out:
 
949
    krb5_storage_free (sp);
 
950
    return ret;
 
951
}