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

« back to all changes in this revision

Viewing changes to src/kdc/fakeka.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
 
/*
2
 
 * COPYRIGHT NOTICE
3
 
 * Copyright (c) 1994 Carnegie Mellon University
4
 
 * All Rights Reserved.
5
 
 * 
6
 
 * Permission to use, copy, modify and distribute this software and its
7
 
 * documentation is hereby granted, provided that both the copyright
8
 
 * notice and this permission notice appear in all copies of the
9
 
 * software, derivative works or modified versions, and any portions
10
 
 * thereof, and that both notices appear in supporting documentation.
11
 
 *
12
 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13
 
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14
 
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15
 
 *
16
 
 * Carnegie Mellon requests users of this software to return to
17
 
 *
18
 
 *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
19
 
 *  School of Computer Science
20
 
 *  Carnegie Mellon University
21
 
 *  Pittsburgh PA 15213-3890
22
 
 *
23
 
 * any improvements or extensions that they make and grant Carnegie Mellon
24
 
 * the rights to redistribute these changes.
25
 
 *
26
 
 * Converted to Kerberos 5 by Ken Hornstein <kenh@cmf.nrl.navy.mil>
27
 
 */
28
 
 
29
 
#include <sys/types.h>
30
 
#include <sys/socket.h>
31
 
#include <netinet/in.h>
32
 
#include <arpa/inet.h>
33
 
#include <stdio.h>
34
 
#include <string.h>
35
 
#include <syslog.h>
36
 
#include <ctype.h>
37
 
#include <errno.h>
38
 
#include <netdb.h>
39
 
#ifdef HAVE_UNISTD_H
40
 
#include <unistd.h>
41
 
#endif
42
 
#ifdef HAVE_STDLIB_H
43
 
#include <stdlib.h>
44
 
#endif
45
 
#ifdef HAVE_MEMORY_H
46
 
#include <memory.h>
47
 
#endif
48
 
 
49
 
#include <krb5.h>
50
 
#include <kadm5/admin.h>
51
 
#include <com_err.h>
52
 
#include <kerberosIV/krb.h>
53
 
#include <kerberosIV/des.h>
54
 
 
55
 
#ifndef LINT
56
 
static char rcsid[]=
57
 
        "$Id: fakeka.c 18009 2006-05-16 01:45:00Z raeburn $";
58
 
#endif
59
 
 
60
 
/*
61
 
 * Misc macros
62
 
 */
63
 
 
64
 
#define PAD_TO(x, a) (((u_long)(x) + (a) - 1) & ~((a) - 1))
65
 
#define min(a, b) ((a) < (b) ? (a) : (b))
66
 
#define MAXFORWARDERS 10
67
 
#define HEADER_LEN 8
68
 
 
69
 
/*
70
 
 * Error values from kautils.h
71
 
 * 
72
 
 * The security errors are:
73
 
 *      KABADTICKET, KABADSERVER, KABADUSER, and KACLOCKSKEW
74
 
 */
75
 
 
76
 
#define KADATABASEINCONSISTENT                   (180480L)
77
 
#define KANOENT                                  (180484L)
78
 
#define KABADREQUEST                             (180490L)     
79
 
#define KABADTICKET                              (180504L)
80
 
#define KABADSERVER                              (180507L)
81
 
#define KABADUSER                                (180508L)
82
 
#define KACLOCKSKEW                              (180514L)
83
 
#define KAINTERNALERROR                          (180518L)
84
 
 
85
 
 
86
 
/*
87
 
 * Type definitions
88
 
 */
89
 
 
90
 
typedef struct packet {
91
 
    char *base;
92
 
    int len;
93
 
    char data[1024];
94
 
} *packet_t;
95
 
 
96
 
typedef struct rx_header {
97
 
    u_int rx_epoch;
98
 
    u_int rx_cid;
99
 
    u_int rx_callnum;
100
 
    u_int rx_seq;
101
 
    u_int rx_serial;
102
 
    u_char rx_type;
103
 
    u_char rx_flags;
104
 
    u_char rx_userstatus;
105
 
    u_char rx_securityindex;
106
 
    u_short rx_spare;
107
 
    u_short rx_service;
108
 
    u_int rx_request;
109
 
} *rx_t;
110
 
 
111
 
 
112
 
/*
113
 
 * Global vars
114
 
 */
115
 
 
116
 
char *progname = "fakeka";              /* needed by libkdb.a */
117
 
char *localrealm = NULL;
118
 
char *localcell = NULL;
119
 
krb5_timestamp req_time;
120
 
kadm5_config_params realm_params;
121
 
int debug = 0;
122
 
 
123
 
 
124
 
/*
125
 
 * This is a table for the "infamous" CMU ticket lifetime conversion.  If
126
 
 * the lifetime is greater than 128, use this table
127
 
 */
128
 
#define MAX_TICKET_LIFETIME 2592000
129
 
static long cmu_seconds[] =
130
 
{
131
 
  38400,  41055,  43894,  46929,  50174,  53643,  57352,  61318,
132
 
  65558,  70091,  74937,  80119,  85658,  91581,  97914,  104684,
133
 
  111922,  119661,  127935,  136781,  146239,  156350,  167161,  178720,
134
 
  191077,  204289,  218415,  233517,  249663,  266926,  285383,  305116,
135
 
  326213,  348769,  372885,  398668,  426233,  455705,  487215,  520903,
136
 
  556921,  595430,  636600,  680618,  727679,  777995,  831789,  889303,
137
 
  950794,  1016536,  1086825,  1161973,  1242317,  1328217,  1420057,  1518246,
138
 
  1623225,  1735463,  1855462,  1983757,  2120924,  2267575,  2424366, 2591999,
139
 
  0
140
 
};
141
 
 
142
 
#if     __STDC__
143
 
/*
144
 
 * Prototypes for all the functions we define
145
 
 */
146
 
 
147
 
void perrorexit(char *);
148
 
void pexit(char *);
149
 
char *kaerror(int);
150
 
int get_princ_key(krb5_context, void *, kadm5_principal_ent_t, des_cblock,
151
 
                  des_key_schedule);
152
 
int check_princ(krb5_context, void *, char *, char *, kadm5_principal_ent_t);
153
 
 
154
 
int make_reply_packet(krb5_context, void *, packet_t, int, int, int,
155
 
                      char *, char *, char *, char *,
156
 
                      des_cblock, des_key_schedule, char *);
157
 
 
158
 
int Authenticate(krb5_context, void *, char *, packet_t, packet_t);
159
 
int GetTicket(krb5_context, void *, char *, packet_t, packet_t);
160
 
void process(krb5_context, void *, char *, packet_t, packet_t);
161
 
#endif
162
 
 
163
 
 
164
 
/*
165
 
 * Helpers for exiting with errors
166
 
 */
167
 
 
168
 
void perrorexit(str)
169
 
char *str;
170
 
{
171
 
    perror(str);
172
 
    exit(1);
173
 
}
174
 
 
175
 
void pexit(str)
176
 
char *str;
177
 
{
178
 
    printf("%s\n", str);
179
 
    exit(1);
180
 
}
181
 
 
182
 
 
183
 
/*
184
 
 * Translate error codes into strings.
185
 
 */
186
 
 
187
 
char *kaerror(e)
188
 
int e;
189
 
{
190
 
    static char buf[1024];
191
 
 
192
 
    switch (e) {
193
 
    case KADATABASEINCONSISTENT:
194
 
        return "database is inconsistent";
195
 
    case KANOENT:
196
 
        return "principal does not exist";
197
 
    case KABADREQUEST:
198
 
        return "request was malformed (bad password)";
199
 
    case KABADTICKET:
200
 
        return "ticket was malformed, invalid, or expired";
201
 
    case KABADSERVER:
202
 
        return "cannot issue tickets for this service";
203
 
    case KABADUSER:
204
 
        return "principal expired";
205
 
    case KACLOCKSKEW:
206
 
        return "client time is too far skewed";
207
 
    case KAINTERNALERROR:
208
 
        return "internal error in fakeka, help!";
209
 
    default:
210
 
        sprintf(buf, "impossible error code %d, help!", e);
211
 
        return buf;
212
 
    }
213
 
    /*NOTREACHED*/
214
 
}
215
 
 
216
 
/*
217
 
 * Syslog facilities
218
 
 */
219
 
typedef struct {
220
 
        int num;
221
 
        char *string;
222
 
} facility_mapping;
223
 
 
224
 
static facility_mapping mappings[] = {
225
 
#ifdef LOG_KERN   
226
 
        { LOG_KERN, "KERN" },
227
 
#endif
228
 
#ifdef LOG_USER
229
 
        { LOG_USER, "USER" },
230
 
#endif
231
 
#ifdef LOG_MAIL
232
 
        { LOG_MAIL, "MAIL" },
233
 
#endif
234
 
#ifdef LOG_DAEMON
235
 
        { LOG_DAEMON, "DAEMON" },
236
 
#endif
237
 
#ifdef LOG_AUTH
238
 
        { LOG_AUTH, "AUTH" },
239
 
#endif
240
 
#ifdef LOG_LPR
241
 
        { LOG_LPR, "LPR" },
242
 
#endif
243
 
#ifdef LOG_NEWS
244
 
        { LOG_NEWS, "NEWS" },
245
 
#endif
246
 
#ifdef LOG_UUCP
247
 
        { LOG_UUCP, "UUCP" },
248
 
#endif
249
 
#ifdef LOG_CRON
250
 
        { LOG_CRON, "CRON" },
251
 
#endif
252
 
#ifdef LOG_LOCAL0
253
 
        { LOG_LOCAL0, "LOCAL0" },
254
 
#endif
255
 
#ifdef LOG_LOCAL1
256
 
        { LOG_LOCAL1, "LOCAL1" },
257
 
#endif
258
 
#ifdef LOG_LOCAL2
259
 
        { LOG_LOCAL2, "LOCAL2" },
260
 
#endif
261
 
#ifdef LOG_LOCAL3
262
 
        { LOG_LOCAL3, "LOCAL3" },
263
 
#endif
264
 
#ifdef LOG_LOCAL4
265
 
        { LOG_LOCAL4, "LOCAL4" },
266
 
#endif
267
 
#ifdef LOG_LOCAL5
268
 
        { LOG_LOCAL5, "LOCAL5" },
269
 
#endif
270
 
#ifdef LOG_LOCAL6
271
 
        { LOG_LOCAL6, "LOCAL6" },
272
 
#endif
273
 
#ifdef LOG_LOCAL7
274
 
        { LOG_LOCAL7, "LOCAL7" },
275
 
#endif
276
 
        { 0, NULL }
277
 
};
278
 
 
279
 
 
280
 
/*
281
 
 * Get the principal's key and key schedule from the db record.
282
 
 *
283
 
 * Life is more complicated in the V5 world.  Since we can have different
284
 
 * encryption types, we have to make sure that we get back a DES key.
285
 
 * Also, we have to try to get back a AFS3 or V4 salted key, since AFS
286
 
 * doesn't know about a V5 style salt.
287
 
 */
288
 
 
289
 
int get_princ_key(context, handle, p, k, s)
290
 
krb5_context context;
291
 
void *handle;
292
 
kadm5_principal_ent_t p;
293
 
des_cblock k;
294
 
des_key_schedule s;
295
 
{       
296
 
    int rv;
297
 
    krb5_keyblock kb;
298
 
    kadm5_ret_t retval;
299
 
 
300
 
    /*
301
 
     * We need to call kadm5_decrypt_key to decrypt the key data
302
 
     * from the principal record.  We _must_ have a encryption type
303
 
     * of DES_CBC_CRC, and we prefer having a salt type of AFS 3 (but
304
 
     * a V4 salt will work as well).  If that fails, then return any
305
 
     * type of key we can find.
306
 
     *
307
 
     * Note that since this uses kadm5_decrypt_key, it means it has to
308
 
     * be compiled with the kadm5srv library.
309
 
     */
310
 
 
311
 
    if ((retval = kadm5_decrypt_key(handle, p, ENCTYPE_DES_CBC_CRC,
312
 
                                    KRB5_KDB_SALTTYPE_AFS3, 0, &kb,
313
 
                                    NULL, NULL)))
314
 
        if ((retval = kadm5_decrypt_key(handle, p, ENCTYPE_DES_CBC_CRC,
315
 
                                        KRB5_KDB_SALTTYPE_V4, 0, &kb,
316
 
                                        NULL, NULL)))
317
 
                if ((retval = kadm5_decrypt_key(handle, p, ENCTYPE_DES_CBC_CRC,
318
 
                                                -1, 0, &kb, NULL, NULL))) {
319
 
                        syslog(LOG_ERR, "Couldn't find any matching key: %s",
320
 
                               error_message(retval));
321
 
                        return KAINTERNALERROR;
322
 
                }
323
 
 
324
 
    /*
325
 
     * Copy the data from our krb5_keyblock to the des_cblock.  Make sure
326
 
     * the size of our key matches the V4/AFS des_cblock.
327
 
     */
328
 
 
329
 
    if (kb.length != sizeof(des_cblock)) {
330
 
        krb5_free_keyblock_contents(context, &kb);
331
 
        syslog(LOG_ERR, "Principal key size of %d didn't match C_Block size"
332
 
               " %d", kb.length, sizeof(des_cblock));
333
 
        return KAINTERNALERROR;
334
 
    }
335
 
 
336
 
    memcpy((char *) k, (char *) kb.contents, sizeof(des_cblock));
337
 
 
338
 
    krb5_free_keyblock_contents(context, &kb);
339
 
 
340
 
    /*
341
 
     * Calculate the des key schedule
342
 
     */
343
 
 
344
 
    rv = des_key_sched(k, s);
345
 
    if (rv) {
346
 
        memset((void *) k, 0, sizeof(k));
347
 
        memset((void *)s, 0, sizeof(s));
348
 
        return KAINTERNALERROR;
349
 
    }
350
 
    return 0;
351
 
}
352
 
 
353
 
 
354
 
/*
355
 
 * Fetch principal from db and validate it.
356
 
 *
357
 
 * Note that this always fetches the key data from the principal (but it
358
 
 * doesn't decrypt it).
359
 
 */
360
 
 
361
 
int check_princ(context, handle, name, inst, p)
362
 
krb5_context context;
363
 
void *handle;
364
 
char *name, *inst;
365
 
kadm5_principal_ent_t p;
366
 
{
367
 
    krb5_principal princ;
368
 
    krb5_error_code code;
369
 
    kadm5_ret_t retcode;
370
 
 
371
 
    /*
372
 
     * Screen out null principals. They are causing crashes here
373
 
     * under HPUX-10.20. - vwelch@ncsa.uiuc.edu 1/6/98
374
 
     */
375
 
    if (!name || (name[0] == '\0')) {
376
 
        syslog(LOG_ERR, "screening out null principal");
377
 
        return KANOENT;
378
 
    }
379
 
 
380
 
    /*
381
 
     * Build a principal from the name and instance (the realm is always
382
 
     * the same).
383
 
     */
384
 
 
385
 
    if ((code = krb5_build_principal_ext(context, &princ, strlen(localrealm),
386
 
                                         localrealm, strlen(name), name,
387
 
                                         strlen(inst), inst, 0))) {
388
 
        syslog(LOG_ERR, "could not build principal: %s", error_message(code));
389
 
        return KAINTERNALERROR;
390
 
    }
391
 
 
392
 
    /*
393
 
     * Fetch the principal from the database -- also fetch the key data.
394
 
     * Note that since this retrieves the key data, it has to be linked with
395
 
     * the kadm5srv library.
396
 
     */
397
 
 
398
 
    if ((retcode = kadm5_get_principal(handle, princ, p,
399
 
                                       KADM5_PRINCIPAL_NORMAL_MASK |
400
 
                                       KADM5_KEY_DATA))) {
401
 
        if (retcode == KADM5_UNK_PRINC) {
402
 
            krb5_free_principal(context, princ);
403
 
            syslog(LOG_INFO, "principal %s.%s does not exist", name, inst);
404
 
            return KANOENT;
405
 
        } else {
406
 
            krb5_free_principal(context, princ);
407
 
            syslog(LOG_ERR, "kadm5_get_principal failed: %s",
408
 
                   error_message(retcode));
409
 
            return KAINTERNALERROR;
410
 
        }
411
 
    }
412
 
 
413
 
    krb5_free_principal(context, princ);
414
 
 
415
 
    /*
416
 
     * Check various things - taken from the KDC code.
417
 
     *
418
 
     * Since we're essentially bypassing the KDC, we need to make sure
419
 
     * that we don't give out a ticket that we shouldn't.
420
 
     */
421
 
 
422
 
    /*
423
 
     * Has the principal expired?
424
 
     */
425
 
 
426
 
    if (p->princ_expire_time && p->princ_expire_time < req_time) {
427
 
        kadm5_free_principal_ent(handle, p);
428
 
        return KABADUSER;
429
 
    }
430
 
 
431
 
    /*
432
 
     * Has the principal's password expired?  Note that we don't
433
 
     * check for the PWCHANGE_SERVICE flag here, since we don't
434
 
     * support password changing.  We do support the REQUIRES_PWCHANGE
435
 
     * flag, though.
436
 
     */
437
 
 
438
 
    if ((p->pw_expiration && p->pw_expiration < req_time) ||
439
 
        (p->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
440
 
        kadm5_free_principal_ent(handle, p);
441
 
        return KABADUSER;
442
 
    }
443
 
 
444
 
    /*
445
 
     * See if the principal is locked out
446
 
     */
447
 
 
448
 
    if (p->attributes & KRB5_KDB_DISALLOW_ALL_TIX) {
449
 
        kadm5_free_principal_ent(handle, p);
450
 
        return KABADUSER;
451
 
    }
452
 
 
453
 
    /*
454
 
     * There's no way we can handle hardware preauth, so
455
 
     * disallow tickets with this flag set.
456
 
     */
457
 
 
458
 
    if (p->attributes & KRB5_KDB_REQUIRES_HW_AUTH) {
459
 
        kadm5_free_principal_ent(handle, p);
460
 
        return KABADUSER;
461
 
    }
462
 
 
463
 
    /*
464
 
     * Must be okay, then
465
 
     */
466
 
 
467
 
    return 0;
468
 
}
469
 
 
470
 
 
471
 
/*
472
 
 * Create an rx reply packet in "packet" using the provided data.
473
 
 * The caller is responsible for zeroing key and sched.
474
 
 */
475
 
 
476
 
int make_reply_packet(context, handle, reply, challenge_response, start_time,
477
 
                      end_time, cname, cinst, sname, sinst, key, sched, label)
478
 
krb5_context context;
479
 
void *handle;
480
 
packet_t reply;
481
 
int challenge_response, start_time, end_time;
482
 
char *cname, *cinst, *sname, *sinst;
483
 
des_cblock key;
484
 
des_key_schedule sched;
485
 
char *label;
486
 
{
487
 
    int rv, n, maxn, v4life, *enclenp, *ticklenp;
488
 
    u_char *p, *enc, *ticket;
489
 
    kadm5_principal_ent_rec cprinc, sprinc;
490
 
    des_cblock skey, new_session_key;
491
 
    des_key_schedule ssched;
492
 
    krb5_deltat lifetime;
493
 
 
494
 
    rv = 0;
495
 
 
496
 
    rv = check_princ(context, handle, cname, cinst, &cprinc);
497
 
    if (rv)
498
 
        return rv;
499
 
 
500
 
    rv = check_princ(context, handle, sname, sinst, &sprinc);
501
 
    if (rv) {
502
 
        kadm5_free_principal_ent(handle, &cprinc);
503
 
        return rv;
504
 
    }
505
 
 
506
 
    /* 
507
 
     * Bound ticket lifetime by max lifetimes of user and service.
508
 
     *
509
 
     * Since V5 already stores everything in Unix epoch timestamps like
510
 
     * AFS, these calculations are much simpler.
511
 
     */
512
 
 
513
 
    lifetime = end_time - start_time;
514
 
    lifetime = min(lifetime, cprinc.max_life);
515
 
    lifetime = min(lifetime, sprinc.max_life);
516
 
    lifetime = min(lifetime, realm_params.max_life);
517
 
 
518
 
    end_time = start_time + lifetime;
519
 
 
520
 
    /*
521
 
     * But we have to convert back to V4-style lifetimes
522
 
     */
523
 
 
524
 
    v4life = lifetime / 300;
525
 
    if (v4life > 127) {
526
 
        /*
527
 
         * Use the CMU algorithm instead
528
 
         */
529
 
        long *clist = cmu_seconds;
530
 
        while (*clist && *clist < lifetime) clist++;
531
 
        v4life = 128 + (clist - cmu_seconds);
532
 
    }
533
 
 
534
 
    /*
535
 
     * If this is for afs and the instance is the local cell name
536
 
     * then we assume we added the instance in GetTickets to
537
 
     * identify the afs key in the kerberos database. This is for
538
 
     * cases where the afs cell name is different from the kerberos
539
 
     * realm name. We now want to remove the instance so it doesn't
540
 
     * cause klog to barf.
541
 
     */
542
 
    if (!strcmp(sname, "afs") && (strcasecmp(sinst, localcell) == 0))
543
 
        sinst[0] = '\0';
544
 
 
545
 
    /*
546
 
     * All the data needed to construct the ticket is ready, so do it.
547
 
     */
548
 
 
549
 
    p = (unsigned char *) reply->base;
550
 
    maxn = reply->len;
551
 
    n = 0;
552
 
 
553
 
#define ERR(x) do { rv = x ; goto error; } while (0)
554
 
#define ADVANCE(x) { if ((n += x) > maxn) ERR(KAINTERNALERROR); else p += x;}
555
 
#define PUT_CHAR(x) { *p = (x); ADVANCE(1); }
556
 
#define PUT_INT(x) { int q = ntohl(x); memcpy(p, (char *)&q, 4); ADVANCE(4); }
557
 
#define PUT_STR(x) { strcpy((char *) p, x); ADVANCE(strlen(x) + 1); }
558
 
 
559
 
    ADVANCE(28);
560
 
    PUT_INT(0x2bc);
561
 
 
562
 
    enclenp = (int *)p;
563
 
    PUT_INT(0);         /* filled in later */
564
 
 
565
 
    enc = p;
566
 
    PUT_INT(0);
567
 
    PUT_INT(challenge_response);
568
 
 
569
 
    /*
570
 
     * new_session_key is created here, and remains in the clear
571
 
     * until just before we return.
572
 
     */
573
 
    des_new_random_key(new_session_key);
574
 
    memcpy(p, new_session_key, 8);
575
 
 
576
 
    ADVANCE(8);
577
 
    PUT_INT(start_time);
578
 
    PUT_INT(end_time);
579
 
    PUT_INT(sprinc.kvno);
580
 
 
581
 
    ticklenp = (int *)p;
582
 
    PUT_INT(0);         /* filled in later */
583
 
 
584
 
    PUT_STR(cname);
585
 
    PUT_STR(cinst);
586
 
    PUT_STR("");
587
 
    PUT_STR(sname);
588
 
    PUT_STR(sinst);
589
 
 
590
 
    ticket = p;
591
 
    PUT_CHAR(0);        /* flags, always 0 */
592
 
    PUT_STR(cname);
593
 
    PUT_STR(cinst);
594
 
    PUT_STR("");
595
 
    PUT_INT(0);         /* would be ip address */
596
 
 
597
 
    memcpy(p, new_session_key, 8);
598
 
 
599
 
    ADVANCE(8);
600
 
 
601
 
    PUT_CHAR(v4life);
602
 
    PUT_INT(start_time);
603
 
    PUT_STR(sname);
604
 
    PUT_STR(sinst);
605
 
 
606
 
    ADVANCE(PAD_TO(p - ticket, 8) - (p - ticket));
607
 
 
608
 
    *ticklenp = ntohl(p - ticket);
609
 
 
610
 
    rv = get_princ_key(context, handle, &sprinc, skey, ssched);
611
 
    if (rv)
612
 
        return rv;
613
 
    des_pcbc_encrypt((C_Block *) ticket, (C_Block *) ticket, p - ticket,
614
 
                     ssched, (C_Block *) skey, ENCRYPT);
615
 
    memset(skey, 0, sizeof(skey));
616
 
    memset(ssched, 0, sizeof(ssched));
617
 
 
618
 
    PUT_STR(label);     /* "tgsT" or "gtkt" */
619
 
    ADVANCE(-1);        /* back up over string terminator */
620
 
 
621
 
    ADVANCE(PAD_TO(p - enc, 8) - (p - enc));
622
 
#undef  ERR
623
 
#undef  ADVANCE
624
 
#undef  PUT_CHAR
625
 
#undef  PUT_INT
626
 
#undef  PUT_STR
627
 
 
628
 
    *enclenp = ntohl(p - enc);
629
 
    des_pcbc_encrypt((C_Block *) enc, (C_Block *) enc, p - enc, sched,
630
 
                     (C_Block *) key, ENCRYPT);
631
 
    reply->len = n;
632
 
 
633
 
  error:
634
 
    memset(new_session_key, 0, sizeof(new_session_key));
635
 
    kadm5_free_principal_ent(handle, &cprinc);
636
 
    kadm5_free_principal_ent(handle, &sprinc);
637
 
 
638
 
    return rv;
639
 
}
640
 
 
641
 
#define ERR(x) do { rv = x; goto error; } while (0)
642
 
#define ADVANCE(x) { if ((n += x) > maxn) ERR(KABADREQUEST); else p += x; }
643
 
#define GET_INT(x) { int q; memcpy((char *)&q, p, 4); x = ntohl(q); ADVANCE(4); }
644
 
#define GET_CHAR(x) { x = *p; ADVANCE(1); }
645
 
#define GET_PSTR(x) \
646
 
    { \
647
 
        GET_INT(len); \
648
 
        if (len > sizeof(x) - 1) ERR(KABADREQUEST); \
649
 
        memcpy(x, p, len); \
650
 
        x[len] = 0; \
651
 
        ADVANCE(PAD_TO(len, 4)); \
652
 
    }
653
 
 
654
 
#define GET_STR(x) \
655
 
    { \
656
 
        len = strlen(p); \
657
 
        if (len > sizeof(x) - 1) ERR(KABADREQUEST); \
658
 
        strcpy(x, p); \
659
 
        ADVANCE(len + 1); \
660
 
    }
661
 
 
662
 
 
663
 
/*
664
 
 * Process an Authenticate request.
665
 
 */
666
 
 
667
 
int Authenticate(context, handle, from, req, reply)
668
 
krb5_context context;
669
 
void *handle;
670
 
char *from;
671
 
packet_t req, reply;
672
 
{
673
 
    int rv, n, maxn;
674
 
    int len, start_time, end_time, challenge;
675
 
    char name[ANAME_SZ+1], inst[INST_SZ+1], *p;
676
 
    kadm5_principal_ent_rec cprinc;
677
 
    des_cblock ckey;
678
 
    des_key_schedule csched;
679
 
    int free_princ_ent = 0;
680
 
 
681
 
    rv = 0;
682
 
 
683
 
    p = req->base;
684
 
    maxn = req->len;
685
 
    n = 0;
686
 
 
687
 
    ADVANCE(32);
688
 
 
689
 
    GET_PSTR(name);
690
 
    GET_PSTR(inst);
691
 
 
692
 
    if (debug)
693
 
        fprintf(stderr, "Authenticating %s.%s\n", name, inst);
694
 
 
695
 
    rv = check_princ(context, handle, name, inst, &cprinc);
696
 
    if (rv)
697
 
        ERR(rv);
698
 
 
699
 
    free_princ_ent = 1;
700
 
 
701
 
    GET_INT(start_time);
702
 
    GET_INT(end_time);
703
 
 
704
 
    GET_INT(len);
705
 
    if (len != 8)
706
 
        ERR(KABADREQUEST);
707
 
 
708
 
    /*
709
 
     * ckey and csched are set here and remain in the clear
710
 
     * until just before we return.
711
 
     */
712
 
 
713
 
    rv = get_princ_key(context, handle, &cprinc, ckey, csched);
714
 
    if (rv)
715
 
        ERR(rv);
716
 
    des_pcbc_encrypt((C_Block *) p, (C_Block *) p, 8, csched,
717
 
                     (C_Block *) ckey, DECRYPT);
718
 
 
719
 
    GET_INT(challenge);
720
 
 
721
 
    rv = memcmp(p, "gTGS", 4);
722
 
    if (rv)
723
 
        ERR(KABADREQUEST);
724
 
    ADVANCE(4);
725
 
 
726
 
    /* ignore the rest */
727
 
    ADVANCE(8);
728
 
 
729
 
    /*
730
 
     * We have all the data from the request, now generate the reply.
731
 
     */
732
 
 
733
 
    rv =  make_reply_packet(context, handle, reply, challenge + 1, start_time,
734
 
                            end_time, name, inst, "krbtgt", localcell,
735
 
                            ckey, csched, "tgsT");
736
 
  error:
737
 
    memset(ckey, 0, sizeof(ckey));
738
 
    memset(csched, 0, sizeof(csched));
739
 
 
740
 
    syslog(LOG_INFO, "authenticate: %s.%s from %s", name, inst, from);
741
 
    if (rv) {
742
 
        syslog(LOG_INFO, "... failed due to %s", kaerror(rv));
743
 
    }
744
 
    if (free_princ_ent)
745
 
        kadm5_free_principal_ent(handle, &cprinc);
746
 
    return rv;
747
 
}
748
 
 
749
 
 
750
 
/*
751
 
 * Process a GetTicket rpc.
752
 
 */
753
 
 
754
 
int GetTicket(context, handle, from, req, reply)
755
 
krb5_context context;
756
 
void *handle;
757
 
char *from;
758
 
packet_t req, reply;
759
 
{
760
 
    int rv, n, maxn, len, ticketlen;
761
 
    char *p;
762
 
    u_int kvno, start_time, end_time, times[2], flags, ipaddr;
763
 
    u_int tgt_start_time, tgt_end_time, lifetime;
764
 
    char rname[ANAME_SZ+1], rinst[INST_SZ+1];   /* requested principal */
765
 
    char sname[ANAME_SZ+1], sinst[INST_SZ+1];   /* service principal (TGT) */
766
 
    char cname[ANAME_SZ+1], cinst[INST_SZ+1];   /* client principal */
767
 
    char cell[REALM_SZ+1], realm[REALM_SZ+1];
768
 
    char enctimes[8 + 1], ticket[1024];
769
 
    u_char tgt_lifetime;
770
 
    kadm5_principal_ent_rec cprinc;
771
 
    des_cblock ckey, session_key;
772
 
    des_key_schedule csched, session_sched;
773
 
    int free_princ_ent = 0;
774
 
 
775
 
    rv = 0;
776
 
 
777
 
    /* 
778
 
     * Initialize these so we don't crash trying to print them in
779
 
     * case they don't get filled in.
780
 
     */
781
 
    strcpy(rname, "Unknown");
782
 
    strcpy(rinst, "Unknown");
783
 
    strcpy(sname, "Unknown");
784
 
    strcpy(sinst, "Unknown");
785
 
    strcpy(cname, "Unknown");
786
 
    strcpy(cinst, "Unknown");
787
 
    strcpy(cell, "Unknown");
788
 
    strcpy(realm, "Unknown");
789
 
    
790
 
    p = req->base;
791
 
    maxn = req->len;
792
 
    n = 0;
793
 
 
794
 
    ADVANCE(32);
795
 
 
796
 
    GET_INT(kvno);
797
 
 
798
 
    GET_PSTR(cell);
799
 
    if (!cell[0])
800
 
        strcpy(cell, localcell);
801
 
 
802
 
    if (debug)
803
 
        fprintf(stderr, "Cell is %s\n", cell);
804
 
 
805
 
    memset(ticket, 0, sizeof(ticket));
806
 
    GET_PSTR(ticket);
807
 
    ticketlen = len;    /* hacky hack hack */
808
 
    GET_PSTR(rname);
809
 
    GET_PSTR(rinst);
810
 
 
811
 
    if (debug)
812
 
        fprintf(stderr, "Request for %s/%s\n", rname, rinst);
813
 
 
814
 
    GET_PSTR(enctimes); /* still encrypted */
815
 
    if (len != 8)       /* hack and hack again */
816
 
        ERR(KABADREQUEST);
817
 
 
818
 
    /* ignore the rest */
819
 
    ADVANCE(8);
820
 
 
821
 
    /*
822
 
     * That's it for the packet, now decode the embedded ticket.
823
 
     */
824
 
 
825
 
    rv = check_princ(context, handle, "krbtgt", cell, &cprinc);
826
 
    if (rv)
827
 
        ERR(rv);
828
 
 
829
 
    free_princ_ent = 1;
830
 
 
831
 
    rv = get_princ_key(context, handle, &cprinc, ckey, csched);
832
 
    if (rv)
833
 
        ERR(rv);
834
 
    des_pcbc_encrypt((C_Block *) ticket, (C_Block *) ticket, ticketlen, csched,
835
 
                     (C_Block *) ckey, DECRYPT);
836
 
    memset(ckey, 0, sizeof(ckey));
837
 
    memset(csched, 0, sizeof(csched));
838
 
 
839
 
    /*
840
 
     * The ticket's session key is now in the clear in the ticket buffer.
841
 
     * We zero it just before returning.
842
 
     */
843
 
 
844
 
    p = ticket;
845
 
    maxn = ticketlen;
846
 
    n = 0;
847
 
 
848
 
    GET_CHAR(flags);
849
 
    GET_STR(cname);
850
 
    GET_STR(cinst);
851
 
    GET_STR(realm);
852
 
    GET_INT(ipaddr);
853
 
    memcpy(session_key, p, 8);
854
 
    ADVANCE(8);
855
 
 
856
 
    GET_CHAR(tgt_lifetime);
857
 
    GET_INT(tgt_start_time);
858
 
    GET_STR(sname);
859
 
    GET_STR(sinst);
860
 
 
861
 
    if (debug)
862
 
        fprintf(stderr,
863
 
                "ticket: %s.%s@%s for %s.%s\n",
864
 
                cname, cinst, realm, sname, sinst);
865
 
 
866
 
    /*
867
 
     * ok, we've got the ticket unpacked.
868
 
     * now decrypt the start and end times.
869
 
     */
870
 
 
871
 
    rv = des_key_sched(session_key, session_sched);
872
 
    if (rv) 
873
 
        ERR(KABADTICKET);
874
 
 
875
 
    des_ecb_encrypt((C_Block *) enctimes, (C_Block *) times, session_sched,
876
 
                    DECRYPT);
877
 
    start_time = ntohl(times[0]);
878
 
    end_time = ntohl(times[1]);
879
 
 
880
 
    /*
881
 
     * All the info we need is now available.
882
 
     * Now validate the request.
883
 
     */
884
 
 
885
 
    /*
886
 
     * This translator requires that the flags and IP address
887
 
     * in the ticket be zero, because we always set them that way,
888
 
     * and we want to accept only tickets that we generated.
889
 
     * 
890
 
     * Are the flags and IP address fields 0?
891
 
     */
892
 
    if (flags || ipaddr) {
893
 
        if (debug)
894
 
            fprintf(stderr, "ERROR: flags or ipaddr field non-zero\n");
895
 
        ERR(KABADTICKET);
896
 
    }
897
 
    /*
898
 
     * Is the supplied ticket a tgt?
899
 
     */
900
 
    if (strcmp(sname, "krbtgt")) {
901
 
        if (debug)
902
 
            fprintf(stderr, "ERROR: not for krbtgt service\n");
903
 
        ERR(KABADTICKET);
904
 
    }
905
 
 
906
 
    /*
907
 
     * This translator does not allow MIT-style cross-realm access.
908
 
     * Is this a cross-realm ticket?
909
 
     */
910
 
    if (strcasecmp(sinst, localcell)) {
911
 
        if (debug)
912
 
            fprintf(stderr,
913
 
                    "ERROR: Service instance (%s) differs from local cell\n",
914
 
                    sinst);
915
 
        ERR(KABADTICKET);
916
 
    }
917
 
 
918
 
    /*
919
 
     * This translator does not issue cross-realm tickets,
920
 
     * since klog doesn't use this feature.
921
 
     * Is the request for a cross-realm ticket?
922
 
     */
923
 
    if (strcasecmp(cell, localcell)) {
924
 
        if (debug)
925
 
            fprintf(stderr, "ERROR: Cell %s != local cell", cell);
926
 
        ERR(KABADTICKET);
927
 
    }
928
 
 
929
 
    /*
930
 
     * Even if we later decide to issue cross-realm tickets,
931
 
     * we should not permit "realm hopping".
932
 
     * This means that the client's realm should match
933
 
     * the realm of the tgt with whose key we are supposed
934
 
     * to decrypt the ticket.  I think.
935
 
     */
936
 
    if (*realm && strcasecmp(realm, cell)) {
937
 
        if (debug)
938
 
            fprintf(stderr, "ERROR: Realm %s != cell %s\n", realm, cell);
939
 
        ERR(KABADTICKET);
940
 
    }
941
 
 
942
 
    /*
943
 
     * This translator issues service tickets only for afs,
944
 
     * since klog is the only client that should be using it.
945
 
     * Is the requested service afs?
946
 
     *
947
 
     * Note: to make EMT work, we're allowing tickets for emt/admin and
948
 
     * adm/admin.
949
 
     */
950
 
    if (! ((strcmp(rname, "afs") == 0 && ! *rinst) ||
951
 
           (strcmp(rname, "emt") == 0 && strcmp(rinst, "admin") == 0) ||
952
 
           (strcmp(rname, "adm") == 0 && strcmp(rinst, "admin") == 0)))
953
 
        ERR(KABADSERVER);
954
 
 
955
 
    /*
956
 
     * If the local realm name and cell name differ and the user
957
 
     * is in the local cell and has requested a ticket of afs. (no
958
 
     * instance, then we actually want to get a ticket for
959
 
     * afs/<cell name>@<realm name>
960
 
     */
961
 
    if ((strcmp(rname, "afs") == 0) && !*rinst &&
962
 
        strcmp(localrealm, localcell) &&
963
 
        (strcasecmp(cell, localcell) == 0)) {
964
 
        char *c;
965
 
 
966
 
        strcpy(rinst, localcell);
967
 
 
968
 
        for (c = rinst; *c != NULL; c++)
969
 
            *c = (char) tolower( (int) *c);
970
 
 
971
 
        if (debug)
972
 
            fprintf(stderr, "Getting ticket for afs/%s\n", localcell);
973
 
    }
974
 
   
975
 
    /*
976
 
     * Even if we later decide to issue service tickets for
977
 
     * services other than afs, we should still disallow
978
 
     * the "changepw" and "krbtgt" services.
979
 
     */
980
 
    if (!strcmp(rname, "changepw") || !strcmp(rname, "krbtgt"))
981
 
        ERR(KABADSERVER);
982
 
 
983
 
    /*
984
 
     * Is the tgt valid yet?  (ie. is the start time in the future)
985
 
     */
986
 
    if (req_time < tgt_start_time - CLOCK_SKEW) {
987
 
        if (debug)
988
 
            fprintf(stderr, "ERROR: Ticket not yet valid\n");
989
 
        ERR(KABADTICKET);
990
 
    }
991
 
 
992
 
    /*
993
 
     * Has the tgt expired?  (ie. is the end time in the past)
994
 
     *
995
 
     * Sigh, convert from V4 lifetimes back to Unix epoch times.
996
 
     */
997
 
 
998
 
    if (tgt_lifetime < 128)
999
 
        tgt_end_time = tgt_start_time + tgt_lifetime * 300;
1000
 
    else if (tgt_lifetime < 192)
1001
 
        tgt_end_time = tgt_start_time + cmu_seconds[tgt_lifetime - 128];
1002
 
    else
1003
 
        tgt_end_time = tgt_start_time + MAX_TICKET_LIFETIME;
1004
 
 
1005
 
    if (tgt_end_time < req_time) {
1006
 
        if (debug)
1007
 
            fprintf(stderr, "ERROR: Ticket expired\n");
1008
 
        ERR(KABADTICKET);
1009
 
    }
1010
 
 
1011
 
    /*
1012
 
     * This translator uses the requested start time as a cheesy
1013
 
     * authenticator, since the KA protocol does not have an
1014
 
     * explicit authenticator.  We can do this since klog always
1015
 
     * requests a start time equal to the current time.
1016
 
     * 
1017
 
     * Is the requested start time approximately now?
1018
 
     */
1019
 
    if (abs(req_time - start_time) > CLOCK_SKEW)
1020
 
        ERR(KACLOCKSKEW);
1021
 
 
1022
 
    /*
1023
 
     * The new ticket's lifetime is the minimum of:
1024
 
     * 1.  remainder of tgt's lifetime
1025
 
     * 2.  requested lifetime
1026
 
     * 
1027
 
     * This is further limited by the client and service's max lifetime
1028
 
     * in make_reply_packet().
1029
 
     */
1030
 
 
1031
 
    lifetime = tgt_end_time - req_time;
1032
 
    lifetime = min(lifetime, end_time - start_time);
1033
 
    end_time = req_time + lifetime;
1034
 
 
1035
 
    /*
1036
 
     * We have all the data from the request, now generate the reply.
1037
 
     */
1038
 
 
1039
 
    rv = make_reply_packet(context, handle, reply, 0, start_time, end_time,
1040
 
                           cname, cinst, rname, rinst,
1041
 
                           session_key, session_sched, "gtkt");
1042
 
  error:
1043
 
    memset(ticket, 0, sizeof(ticket));
1044
 
    memset(session_key, 0, sizeof(session_key));
1045
 
    memset(session_sched, 0, sizeof(session_sched));
1046
 
 
1047
 
    if (free_princ_ent)
1048
 
        kadm5_free_principal_ent(handle, &cprinc);
1049
 
 
1050
 
    syslog(LOG_INFO, "getticket: %s.%s from %s for %s.%s",
1051
 
           cname, cinst, from, rname, rinst);
1052
 
    if (rv) {
1053
 
        syslog(LOG_INFO, "... failed due to %s", kaerror(rv));
1054
 
    }
1055
 
    return rv;
1056
 
}
1057
 
 
1058
 
 
1059
 
#undef  ERR
1060
 
#undef  ADVANCE
1061
 
#undef  GET_INT
1062
 
#undef  GET_PSTR
1063
 
#undef  GET_STR
1064
 
 
1065
 
/*
1066
 
 * Convert the request into a reply.
1067
 
 * Returns 0 on success.
1068
 
 */
1069
 
 
1070
 
void process(context, handle, from, req, reply)
1071
 
krb5_context context;
1072
 
void *handle;
1073
 
char *from;
1074
 
packet_t req, reply;
1075
 
{
1076
 
    int rv;
1077
 
    rx_t req_rx = (rx_t)req->base;
1078
 
    rx_t reply_rx = (rx_t)reply->base;
1079
 
    int service, request;
1080
 
 
1081
 
    service = ntohs(req_rx->rx_service);
1082
 
    request = ntohl(req_rx->rx_request);
1083
 
 
1084
 
    /* ignore everything but type 1 */
1085
 
    if (req_rx->rx_type != 1) {
1086
 
        reply->len = 0;
1087
 
        return;
1088
 
    }
1089
 
 
1090
 
    /* copy the rx header and change the flags */
1091
 
    *reply_rx = *req_rx;
1092
 
    reply_rx->rx_flags = 4;
1093
 
 
1094
 
    rv = -1;
1095
 
 
1096
 
    if (service == 0x2db && (request == 0x15 || request == 0x16)) {
1097
 
        if (debug)
1098
 
            fprintf(stderr, "Handling Authenticate request\n");
1099
 
        rv = Authenticate(context, handle, from, req, reply);
1100
 
    }
1101
 
    if (service == 0x2dc && request == 0x17) {
1102
 
        if (debug)
1103
 
            fprintf(stderr, "Handling GetTicket request\n");
1104
 
        rv = GetTicket(context, handle, from, req, reply);
1105
 
    }
1106
 
/*
1107
 
    if (service == 0x2db && request == 0x1) {
1108
 
        rv = Authenticate_old(from, req, reply);
1109
 
    }
1110
 
    if (service == 0x2dc && request == 0x3) {
1111
 
        rv = GetTicket_old(from, req, reply);
1112
 
    }
1113
 
 */
1114
 
    if (rv == -1) {
1115
 
        syslog(LOG_INFO, "bogus request %d/%d", service, request);
1116
 
        rv = KABADREQUEST;
1117
 
    }
1118
 
 
1119
 
    if (rv) {
1120
 
        /* send the error back to rx */
1121
 
        reply->len = sizeof (*reply_rx);
1122
 
 
1123
 
        reply_rx->rx_type = 4;
1124
 
        reply_rx->rx_flags = 0;
1125
 
        reply_rx->rx_request = ntohl(rv);
1126
 
    }
1127
 
}
1128
 
 
1129
 
 
1130
 
int main(argc, argv)
1131
 
int argc;
1132
 
char **argv;
1133
 
{
1134
 
    int s, rv, ch, mflag = 0;
1135
 
    u_short port;
1136
 
    struct sockaddr_in sin;
1137
 
    int forwarders[MAXFORWARDERS], num_forwarders;
1138
 
    krb5_context context;
1139
 
    krb5_error_code code;
1140
 
    krb5_keyblock mkey;
1141
 
    krb5_principal master_princ;
1142
 
    kadm5_principal_ent_rec master_princ_rec;
1143
 
    void *handle;
1144
 
    facility_mapping *mapping;
1145
 
    int facility = LOG_DAEMON;
1146
 
 
1147
 
    extern char *optarg;
1148
 
 
1149
 
    port = 7004;
1150
 
    num_forwarders = 0;
1151
 
 
1152
 
    /*
1153
 
     * Parse args.
1154
 
     */
1155
 
    while ((ch = getopt(argc, argv, "c:df:l:mp:r:")) != -1) {
1156
 
        switch (ch) {
1157
 
        case 'c':
1158
 
            localcell = optarg;
1159
 
            break;
1160
 
        case 'd':
1161
 
            debug++;
1162
 
            break;
1163
 
        case 'f': {
1164
 
            struct hostent *hp;
1165
 
 
1166
 
            if (num_forwarders++ >= MAXFORWARDERS)
1167
 
                pexit("too many forwarders\n");
1168
 
 
1169
 
            hp = gethostbyname(optarg);
1170
 
            if (!hp) {
1171
 
                printf("unknown host %s\n", optarg);
1172
 
                exit(1);
1173
 
            }
1174
 
            forwarders[num_forwarders - 1] = *(int *)hp->h_addr;
1175
 
 
1176
 
            break;
1177
 
        }
1178
 
        case 'l':
1179
 
            for (mapping = mappings; mapping->string != NULL; mapping++)
1180
 
                if (strcmp(mapping->string, optarg) == 0)
1181
 
                    break;
1182
 
 
1183
 
                if (mapping->string == NULL) {
1184
 
                    printf("Unknown facility \"%s\"\n", optarg);
1185
 
                    exit(1);
1186
 
                }
1187
 
 
1188
 
                facility = mapping->num;
1189
 
                break;
1190
 
        case 'm':
1191
 
            mflag = 1;
1192
 
            break;
1193
 
        case 'p':
1194
 
            if (isdigit(*optarg)) {
1195
 
                port = atoi(optarg);
1196
 
            }
1197
 
            else {
1198
 
                struct servent *sp;
1199
 
 
1200
 
                sp = getservbyname(optarg, "udp");
1201
 
                if (!sp) {
1202
 
                    printf("unknown service %s\n", optarg);
1203
 
                    exit(1);
1204
 
                }
1205
 
                port = sp->s_port;
1206
 
            }
1207
 
            break;
1208
 
        case 'r':
1209
 
            localrealm = optarg;
1210
 
            break;
1211
 
        default:
1212
 
            printf("usage: %s [-c cell] [-d] [-f forwarder-host] [-l facility ] [-p port] [-r realm]\n",
1213
 
                   argv[0]);
1214
 
            exit(1);
1215
 
        }
1216
 
    }
1217
 
 
1218
 
    openlog("fakeka", LOG_PID, facility);
1219
 
 
1220
 
    port = htons(port);
1221
 
 
1222
 
    /*
1223
 
     * Set up the socket.
1224
 
     */
1225
 
 
1226
 
    s = socket(AF_INET, SOCK_DGRAM, 0);
1227
 
    if (s < 0)
1228
 
        perrorexit("Couldn't create socket");
1229
 
 
1230
 
    sin.sin_family = AF_INET;
1231
 
    sin.sin_addr.s_addr = 0;
1232
 
    sin.sin_port = port;
1233
 
 
1234
 
    rv = bind(s, (struct sockaddr *)&sin, sizeof(sin));
1235
 
    if (rv < 0)
1236
 
        perrorexit("Couldn't bind socket");
1237
 
 
1238
 
    /*
1239
 
     * Initialize kerberos stuff and kadm5 stuff.
1240
 
     */
1241
 
 
1242
 
    if ((code = krb5int_init_context_kdc(&context))) {
1243
 
        com_err(argv[0], code, "while initializing Kerberos");
1244
 
        exit(1);
1245
 
    }
1246
 
 
1247
 
    if (!localrealm && (code = krb5_get_default_realm(context, &localrealm))) {
1248
 
        com_err(argv[0], code, "while getting local realm");
1249
 
        exit(1);
1250
 
    }
1251
 
 
1252
 
    if (!localcell)
1253
 
        localcell = localrealm;
1254
 
 
1255
 
    if ((code = kadm5_init_with_password(progname, NULL, KADM5_ADMIN_SERVICE,
1256
 
                                         NULL, KADM5_STRUCT_VERSION,
1257
 
                                         KADM5_API_VERSION_2,
1258
 
                                         (char **) NULL, /* db_args */
1259
 
                                         &handle))) {
1260
 
        com_err(argv[0], code, "while initializing Kadm5");
1261
 
        exit(1);
1262
 
    }
1263
 
 
1264
 
    if ((code = kadm5_get_config_params(context, 1, NULL,
1265
 
                                        &realm_params))) {
1266
 
        com_err(argv[0], code, "while getting realm parameters");
1267
 
        exit(1);
1268
 
    }
1269
 
 
1270
 
    if (! (realm_params.mask & KADM5_CONFIG_MAX_LIFE)) {
1271
 
        fprintf(stderr, "Cannot determine maximum ticket lifetime\n");
1272
 
        exit(1);
1273
 
    }
1274
 
 
1275
 
    /*
1276
 
     * We need to initialize the random number generator for DES.  Use
1277
 
     * the master key to do this.
1278
 
     */
1279
 
 
1280
 
    if ((code = krb5_parse_name(context, realm_params.mask &
1281
 
                                KADM5_CONFIG_MKEY_NAME ?
1282
 
                                realm_params.mkey_name : "K/M",
1283
 
                                &master_princ))) {
1284
 
        com_err(argv[0], code, "while parsing master key name");
1285
 
        exit(1);
1286
 
    }
1287
 
 
1288
 
    if ((code = kadm5_get_principal(handle, master_princ, &master_princ_rec,
1289
 
                                    KADM5_KEY_DATA))) {
1290
 
        com_err(argv[0], code, "while getting master key data");
1291
 
        exit(1);
1292
 
    }
1293
 
 
1294
 
    if ((code = kadm5_decrypt_key(handle, &master_princ_rec,
1295
 
                                  ENCTYPE_DES_CBC_CRC, -1, 0, &mkey, NULL,
1296
 
                                  NULL))) {
1297
 
        com_err(argv[0], code, "while decrypting the master key");
1298
 
        exit(1);
1299
 
    }
1300
 
 
1301
 
    des_init_random_number_generator(mkey.contents);
1302
 
 
1303
 
    krb5_free_keyblock_contents(context, &mkey);
1304
 
 
1305
 
    kadm5_free_principal_ent(handle, &master_princ_rec);
1306
 
 
1307
 
    krb5_free_principal(context, master_princ);
1308
 
 
1309
 
    /*
1310
 
     * Fork and go into the background, if requested
1311
 
     */
1312
 
 
1313
 
    if (!debug && mflag && daemon(0, 0)) {
1314
 
        com_err(argv[0], errno, "while detaching from tty");
1315
 
    }
1316
 
 
1317
 
    /*
1318
 
     * rpc server loop.
1319
 
     */
1320
 
 
1321
 
    for (;;) {
1322
 
        struct packet req, reply;
1323
 
        int sinlen, packetlen, i, forwarded;
1324
 
        char *from;
1325
 
 
1326
 
        sinlen = sizeof(sin);
1327
 
        forwarded = 0;
1328
 
 
1329
 
        memset(req.data, 0, sizeof(req.data));
1330
 
        rv = recvfrom(s, req.data, sizeof(req.data),
1331
 
                      0, (struct sockaddr *)&sin, &sinlen);
1332
 
 
1333
 
        if (rv < 0) {
1334
 
            syslog(LOG_ERR, "recvfrom failed: %m");
1335
 
            sleep(1);
1336
 
            continue;
1337
 
        }
1338
 
        packetlen = rv;
1339
 
 
1340
 
        for (i = 0; i < num_forwarders; i++) {
1341
 
            if (sin.sin_addr.s_addr == forwarders[i]) {
1342
 
                forwarded = 1;
1343
 
                break;
1344
 
            }
1345
 
        }
1346
 
 
1347
 
        if ((code = krb5_timeofday(context, &req_time))) {
1348
 
                syslog(LOG_ERR, "krb5_timeofday failed: %s",
1349
 
                       error_message(code));
1350
 
                continue;
1351
 
        }
1352
 
 
1353
 
        memset(reply.data, 0, sizeof(reply.data));
1354
 
        req.len = packetlen;
1355
 
        req.base = req.data;
1356
 
        reply.base = reply.data;
1357
 
        reply.len = sizeof(reply.data);
1358
 
 
1359
 
        if (forwarded) {
1360
 
            struct in_addr ia;
1361
 
 
1362
 
            memcpy(&ia.s_addr, req.data, 4);
1363
 
            from = inet_ntoa(ia);
1364
 
            /*
1365
 
             * copy the forwarder header and adjust the bases and lengths.
1366
 
             */
1367
 
            memcpy(reply.data, req.data, HEADER_LEN);
1368
 
            req.base += HEADER_LEN;
1369
 
            req.len -= HEADER_LEN;
1370
 
            reply.base += HEADER_LEN;
1371
 
            reply.len -= HEADER_LEN;
1372
 
        }
1373
 
        else {
1374
 
            from = inet_ntoa(sin.sin_addr);
1375
 
        }
1376
 
 
1377
 
        process(context, handle, from, &req, &reply);
1378
 
 
1379
 
        if (reply.len == 0)
1380
 
            continue;
1381
 
 
1382
 
        if (forwarded) {
1383
 
            /* re-adjust the length to account for the forwarder header */
1384
 
            reply.len += HEADER_LEN;
1385
 
        }
1386
 
 
1387
 
        rv = sendto(s, reply.data, reply.len,
1388
 
                    0, (struct sockaddr *)&sin, sinlen);
1389
 
        if (rv < 0) {
1390
 
            syslog(LOG_ERR, "sendto failed: %m");
1391
 
            sleep(1);
1392
 
        }
1393
 
    }
1394
 
    /*NOTREACHED*/
1395
 
}