~ubuntu-branches/ubuntu/intrepid/xserver-xgl/intrepid

« back to all changes in this revision

Viewing changes to os/k5auth.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthew Garrett
  • Date: 2006-02-13 14:21:43 UTC
  • Revision ID: james.westby@ubuntu.com-20060213142143-mad6z9xzem7hzxz9
Tags: upstream-7.0.0
ImportĀ upstreamĀ versionĀ 7.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Xorg: k5auth.c,v 1.4 2001/02/09 02:05:23 xorgcvs Exp $ */
 
2
/*
 
3
 
 
4
Copyright 1993, 1994, 1998  The Open Group
 
5
 
 
6
Permission to use, copy, modify, distribute, and sell this software and its
 
7
documentation for any purpose is hereby granted without fee, provided that
 
8
the above copyright notice appear in all copies and that both that
 
9
copyright notice and this permission notice appear in supporting
 
10
documentation.
 
11
 
 
12
The above copyright notice and this permission notice shall be included
 
13
in all copies or substantial portions of the Software.
 
14
 
 
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 
16
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
17
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 
18
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
 
19
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 
20
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 
21
OTHER DEALINGS IN THE SOFTWARE.
 
22
 
 
23
Except as contained in this notice, the name of The Open Group shall
 
24
not be used in advertising or otherwise to promote the sale, use or
 
25
other dealings in this Software without prior written authorization
 
26
from The Open Group.
 
27
 
 
28
*/
 
29
/* $XFree86: xc/programs/Xserver/os/k5auth.c,v 3.4 2001/01/17 22:37:10 dawes Exp $ */
 
30
 
 
31
/*
 
32
 * Kerberos V5 authentication scheme
 
33
 * Author: Tom Yu <tlyu@MIT.EDU>
 
34
 *
 
35
 * Mostly snarfed wholesale from the user_user demo in the
 
36
 * krb5 distribution. (At least the checking part)
 
37
 */
 
38
 
 
39
#ifdef HAVE_DIX_CONFIG_H
 
40
#include <dix-config.h>
 
41
#endif
 
42
 
 
43
#include <sys/types.h>
 
44
#include <sys/socket.h>
 
45
#ifdef TCPCONN
 
46
#include <netinet/in.h>
 
47
#endif
 
48
#ifdef DNETCONN
 
49
#include <netdnet/dn.h>
 
50
#endif
 
51
#include <arpa/inet.h>
 
52
#include <krb5/krb5.h>
 
53
/* 9/93: krb5.h leaks some symbols */
 
54
#undef BITS32
 
55
#undef xfree
 
56
#include <krb5/los-proto.h>
 
57
#include <X11/X.h>
 
58
#include "os.h"
 
59
#include "osdep.h"
 
60
#include <X11/Xproto.h>
 
61
#include <X11/Xfuncs.h>
 
62
#include "dixstruct.h"
 
63
#include <com_err.h>
 
64
#include "Xauth.h"
 
65
 
 
66
extern int (*k5_Vector[256])();
 
67
extern int SendConnSetup();
 
68
extern char *display;           /* need this to generate rcache name */
 
69
 
 
70
static XID krb5_id = ~0L;
 
71
static krb5_principal srvname = NULL; /* service name */
 
72
static char *ccname = NULL;
 
73
static char *ktname = NULL;     /* key table name */
 
74
static char kerror[256];
 
75
 
 
76
/*
 
77
 * tgt_keyproc:
 
78
 *
 
79
 * extract session key from a credentials struct
 
80
 */
 
81
krb5_error_code tgt_keyproc(keyprocarg, principal, vno, key)
 
82
    krb5_pointer keyprocarg;
 
83
    krb5_principal principal;
 
84
    krb5_kvno vno;
 
85
    krb5_keyblock **key;
 
86
{
 
87
    krb5_creds *creds = (krb5_creds *)keyprocarg;
 
88
    
 
89
    return krb5_copy_keyblock(&creds->keyblock, key);
 
90
}
 
91
 
 
92
/*
 
93
 * k5_cmpenc:
 
94
 *
 
95
 * compare "encoded" principals
 
96
 */
 
97
Bool k5_cmpenc(pname, plen, buf)
 
98
    unsigned char *pname;
 
99
    short plen;
 
100
    krb5_data *buf;
 
101
{
 
102
    return (plen == buf->length &&
 
103
            memcmp(pname, buf->data, plen) == 0);
 
104
}
 
105
 
 
106
/*
 
107
 * K5Check:
 
108
 *
 
109
 * This is stage 0 of the krb5 authentication protocol.  It
 
110
 * goes through the current credentials cache and extracts the
 
111
 * primary principal and tgt to send to the client, or as
 
112
 * appropriate, extracts from a keytab.
 
113
 *
 
114
 * The packet sent to the client has the following format:
 
115
 *
 
116
 * CARD8        reqType = 2
 
117
 * CARD8        data    = 0
 
118
 * CARD16       length  = total length of packet (in 32 bit units)
 
119
 * CARD16       plen    = length of encoded principal following
 
120
 * STRING8      princ   = encoded principal
 
121
 * STRING8      ticket  = server tgt
 
122
 *
 
123
 * For client-server authentication, the packet is as follows:
 
124
 *
 
125
 * CARD8        reqType = 3
 
126
 * CARD8        data    = 0
 
127
 * CARD16       length  = total length
 
128
 * STRING8      princ   = encoded principal of server
 
129
 */
 
130
XID K5Check(data_length, data, client, reason)
 
131
    unsigned short data_length;
 
132
    char *data;
 
133
    ClientPtr client;
 
134
    char **reason;
 
135
{
 
136
    krb5_error_code retval;
 
137
    CARD16 tlen;
 
138
    krb5_principal sprinc, cprinc;
 
139
    krb5_ccache cc;
 
140
    krb5_creds *creds;
 
141
    char *outbuf, *cp;
 
142
    krb5_data princ;
 
143
    register char n;
 
144
    xReq prefix;
 
145
 
 
146
    if (krb5_id == ~0L)
 
147
        return ~0L;
 
148
    if (!ccname && !srvname)
 
149
        return ~0L;
 
150
    if (ccname)
 
151
    {
 
152
        if ((creds = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL)
 
153
            return ~0L;
 
154
        if (retval = krb5_cc_resolve(ccname, &cc))
 
155
            return ~0L;
 
156
        bzero((char*)creds, sizeof (krb5_creds));
 
157
        if (retval = krb5_cc_get_principal(cc, &cprinc))
 
158
        {
 
159
            krb5_free_creds(creds);
 
160
            krb5_cc_close(cc);
 
161
            return ~0L;
 
162
        }
 
163
        creds->client = cprinc;
 
164
        if (retval =
 
165
            krb5_build_principal_ext(&sprinc, 
 
166
                                     krb5_princ_realm(creds->client)->length,
 
167
                                     krb5_princ_realm(creds->client)->data,
 
168
                                     6, "krbtgt",
 
169
                                     krb5_princ_realm(creds->client)->length,
 
170
                                     krb5_princ_realm(creds->client)->data,
 
171
                                     0))
 
172
        {
 
173
            krb5_free_creds(creds);
 
174
            krb5_cc_close(cc);
 
175
            return ~0L;
 
176
        }
 
177
        creds->server = sprinc;
 
178
        retval = krb5_get_credentials(KRB5_GC_CACHED, cc, creds);
 
179
        krb5_cc_close(cc);
 
180
        if (retval)
 
181
        {
 
182
            krb5_free_creds(creds);
 
183
            return ~0L;
 
184
        }
 
185
        if (retval = XauKrb5Encode(cprinc, &princ))
 
186
        {
 
187
            krb5_free_creds(creds);
 
188
            return ~0L;
 
189
        }
 
190
        tlen = sz_xReq + 2 + princ.length + creds->ticket.length;
 
191
        prefix.reqType = 2;     /* opcode = authenticate user-to-user */
 
192
    }
 
193
    else if (srvname)
 
194
    {
 
195
        if (retval = XauKrb5Encode(srvname, &princ))
 
196
        {
 
197
            return ~0L;
 
198
        }
 
199
        tlen = sz_xReq + princ.length;
 
200
        prefix.reqType = 3;     /* opcode = authenticate client-server */
 
201
    }
 
202
    prefix.data = 0;            /* stage = 0 */
 
203
    prefix.length = (tlen + 3) >> 2; /* round up to nearest multiple
 
204
                                        of 4 bytes */
 
205
    if (client->swapped)
 
206
    {
 
207
        swaps(&prefix.length, n);
 
208
    }
 
209
    if ((cp = outbuf = (char *)malloc(tlen)) == NULL)
 
210
    {
 
211
        if (ccname)
 
212
        {
 
213
            krb5_free_creds(creds);
 
214
        }
 
215
        free(princ.data);
 
216
        return ~0L;
 
217
    }
 
218
    memcpy(cp, &prefix, sz_xReq);
 
219
    cp += sz_xReq;
 
220
    if (ccname)
 
221
    {
 
222
        memcpy(cp, &princ.length, 2);
 
223
        if (client->swapped)
 
224
        {
 
225
            swaps((CARD16 *)cp, n);
 
226
        }
 
227
        cp += 2;
 
228
    }
 
229
    memcpy(cp, princ.data, princ.length);
 
230
    cp += princ.length;
 
231
    free(princ.data);           /* we don't need that anymore */
 
232
    if (ccname)
 
233
        memcpy(cp, creds->ticket.data, creds->ticket.length);
 
234
    WriteToClient(client, tlen, outbuf);
 
235
    free(outbuf);
 
236
    client->requestVector = k5_Vector; /* hack in our dispatch vector */
 
237
    client->clientState = ClientStateAuthenticating;
 
238
    if (ccname)
 
239
    {
 
240
        ((OsCommPtr)client->osPrivate)->authstate.srvcreds = (pointer)creds; /* save tgt creds */
 
241
        ((OsCommPtr)client->osPrivate)->authstate.ktname = NULL;
 
242
        ((OsCommPtr)client->osPrivate)->authstate.srvname = NULL;
 
243
    }
 
244
    if (srvname)
 
245
    {
 
246
        ((OsCommPtr)client->osPrivate)->authstate.srvcreds = NULL;
 
247
        ((OsCommPtr)client->osPrivate)->authstate.ktname = (pointer)ktname;
 
248
        ((OsCommPtr)client->osPrivate)->authstate.srvname = (pointer)srvname;
 
249
    }
 
250
    ((OsCommPtr)client->osPrivate)->authstate.stageno = 1; /* next stage is 1 */
 
251
    return krb5_id;
 
252
}
 
253
 
 
254
/*
 
255
 * k5_stage1:
 
256
 *
 
257
 * This gets called out of the dispatcher after K5Check frobs with the
 
258
 * client->requestVector.  It accepts the ap_req from the client and verifies
 
259
 * it.  In addition, if the client has set AP_OPTS_MUTUAL_REQUIRED, it then
 
260
 * sends an ap_rep to the client to achieve mutual authentication.
 
261
 *
 
262
 * client stage1 packet format is as follows:
 
263
 *
 
264
 * CARD8        reqType = 1
 
265
 * CARD8        data    = ignored
 
266
 * CARD16       length  = total length
 
267
 * STRING8      data    = the actual ap_req
 
268
 *
 
269
 * stage2 packet sent back to client for mutual authentication:
 
270
 *
 
271
 * CARD8        reqType = 2
 
272
 * CARD8        data    = 2
 
273
 * CARD16       length  = total length
 
274
 * STRING8      data    = the ap_rep
 
275
 */
 
276
int k5_stage1(client)
 
277
    register ClientPtr client;
 
278
{
 
279
    long addrlen;
 
280
    krb5_error_code retval, retval2;
 
281
    register char n;
 
282
    struct sockaddr cli_net_addr;
 
283
    xReq prefix;
 
284
    krb5_principal cprinc;
 
285
    krb5_data buf;
 
286
    krb5_creds *creds = (krb5_creds *)((OsCommPtr)client->osPrivate)->authstate.srvcreds;
 
287
    krb5_keyblock *skey;
 
288
    krb5_address cli_addr, **localaddrs = NULL;
 
289
    krb5_tkt_authent *authdat;
 
290
    krb5_ap_rep_enc_part rep;
 
291
    krb5_int32 ctime, cusec;
 
292
    krb5_rcache rcache = NULL;
 
293
    char *cachename = NULL, *rc_type = NULL, *rc_base = "rcX", *kt = NULL;
 
294
    REQUEST(xReq);
 
295
 
 
296
    if (((OsCommPtr)client->osPrivate)->authstate.stageno != 1)
 
297
    {
 
298
        if (creds)
 
299
            krb5_free_creds(creds);
 
300
        return(SendConnSetup(client, "expected Krb5 stage1 packet"));
 
301
    }
 
302
    addrlen = sizeof (cli_net_addr);
 
303
    if (getpeername(((OsCommPtr)client->osPrivate)->fd,
 
304
                    &cli_net_addr, &addrlen) == -1)
 
305
    {
 
306
        if (creds)
 
307
            krb5_free_creds(creds);
 
308
        return(SendConnSetup(client, "Krb5 stage1: getpeername failed"));
 
309
    }
 
310
    if (cli_net_addr.sa_family == AF_UNSPEC
 
311
#if defined(UNIXCONN) || defined(LOCALCONN) || defined(OS2PIPECONN)
 
312
        || cli_net_addr.sa_family == AF_UNIX
 
313
#endif
 
314
        )                       /* assume local host */
 
315
    {
 
316
        krb5_os_localaddr(&localaddrs);
 
317
        if (!localaddrs || !localaddrs[0])
 
318
        {
 
319
            if (creds)
 
320
                krb5_free_creds(creds);
 
321
            return(SendConnSetup(client, "Krb5 failed to get localaddrs"));
 
322
        }
 
323
        cli_addr.addrtype = localaddrs[0]->addrtype;
 
324
        cli_addr.length = localaddrs[0]->length;
 
325
        cli_addr.contents = localaddrs[0]->contents;
 
326
    }
 
327
    else
 
328
    {
 
329
        cli_addr.addrtype = cli_net_addr.sa_family; /* the values
 
330
                                                       are compatible */
 
331
        switch (cli_net_addr.sa_family)
 
332
        {
 
333
#ifdef TCPCONN
 
334
        case AF_INET:
 
335
            cli_addr.length = sizeof (struct in_addr);
 
336
            cli_addr.contents =
 
337
                (krb5_octet *)&((struct sockaddr_in *)&cli_net_addr)->sin_addr;
 
338
            break;
 
339
#endif
 
340
#ifdef DNETCONN
 
341
        case AF_DECnet:
 
342
            cli_addr.length = sizeof (struct dn_naddr);
 
343
            cli_addr.contents =
 
344
                (krb5_octet *)&((struct sockaddr_dn *)&cli_net_addr)->sdn_add;
 
345
            break;
 
346
#endif
 
347
        default:
 
348
            if (localaddrs)
 
349
                krb5_free_addresses(localaddrs);
 
350
            if (creds)
 
351
                krb5_free_creds(creds);
 
352
            sprintf(kerror, "Krb5 stage1: unknown address family %d from getpeername",
 
353
                    cli_net_addr.sa_family);    
 
354
            return(SendConnSetup(client, kerror));
 
355
        }
 
356
    }
 
357
    if ((rcache = (krb5_rcache)malloc(sizeof(*rcache))) == NULL)
 
358
    {
 
359
        if (localaddrs)
 
360
            krb5_free_addresses(localaddrs);
 
361
        if (creds)
 
362
            krb5_free_creds(creds);
 
363
        return(SendConnSetup(client, "malloc bombed for krb5_rcache"));
 
364
    }
 
365
    if ((rc_type = krb5_rc_default_type()) == NULL)
 
366
        rc_type = "dfl";
 
367
    if (retval = krb5_rc_resolve_type(&rcache, rc_type))
 
368
    {
 
369
        if (localaddrs)
 
370
            krb5_free_addresses(localaddrs);
 
371
        if (creds)
 
372
            krb5_free_creds(creds);
 
373
        free(rcache);
 
374
        strcpy(kerror, "krb5_rc_resolve_type failed: ");
 
375
        strncat(kerror, error_message(retval), 231);
 
376
        return(SendConnSetup(client, kerror));
 
377
    }
 
378
    if ((cachename = (char *)malloc(strlen(rc_base) + strlen(display) + 1))
 
379
        == NULL)
 
380
    {
 
381
        if (localaddrs)
 
382
            krb5_free_addresses(localaddrs);
 
383
        if (creds)
 
384
            krb5_free_creds(creds);
 
385
        free(rcache);
 
386
        return(SendConnSetup(client, "Krb5: malloc bombed for cachename"));
 
387
    }
 
388
    strcpy(cachename, rc_base);
 
389
    strcat(cachename, display);
 
390
    if (retval = krb5_rc_resolve(rcache, cachename))
 
391
    {
 
392
        if (localaddrs)
 
393
            krb5_free_addresses(localaddrs);
 
394
        if (creds)
 
395
            krb5_free_creds(creds);
 
396
        free(rcache);
 
397
        free(cachename);
 
398
        strcpy(kerror, "krb5_rc_resolve failed: ");
 
399
        strncat(kerror, error_message(retval), 236);
 
400
        return(SendConnSetup(client, kerror));
 
401
    }
 
402
    free(cachename);
 
403
    if (krb5_rc_recover(rcache))
 
404
    {
 
405
        extern krb5_deltat krb5_clockskew;
 
406
        if (retval = krb5_rc_initialize(rcache, krb5_clockskew))
 
407
        {
 
408
            if (localaddrs)
 
409
                krb5_free_addresses(localaddrs);
 
410
            if (creds)
 
411
                krb5_free_creds(creds);
 
412
            if (retval2 = krb5_rc_close(rcache))
 
413
            {
 
414
                strcpy(kerror, "krb5_rc_close failed: ");
 
415
                strncat(kerror, error_message(retval2), 238);
 
416
                return(SendConnSetup(client, kerror));
 
417
            }
 
418
            free(rcache);
 
419
            strcpy(kerror, "krb5_rc_initialize failed: ");
 
420
            strncat(kerror, error_message(retval), 233);
 
421
            return(SendConnSetup(client, kerror));
 
422
        }
 
423
    }
 
424
    buf.length = (stuff->length << 2) - sz_xReq;
 
425
    buf.data = (char *)stuff + sz_xReq;
 
426
    if (creds)
 
427
    {
 
428
        retval = krb5_rd_req(&buf,
 
429
                             NULL, /* don't bother with server name */
 
430
                             &cli_addr,
 
431
                             NULL, /* no fetchfrom */
 
432
                             tgt_keyproc,
 
433
                             creds, /* credentials as arg to
 
434
                                       keyproc */
 
435
                             rcache,
 
436
                             &authdat);
 
437
        krb5_free_creds(creds);
 
438
    }
 
439
    else if (kt = (char *)((OsCommPtr)client->osPrivate)->authstate.ktname)
 
440
    {
 
441
        retval = krb5_rd_req(&buf, srvname, &cli_addr, kt, NULL, NULL,
 
442
                             rcache, &authdat);
 
443
        ((OsCommPtr)client->osPrivate)->authstate.ktname = NULL;
 
444
    }
 
445
    else
 
446
    {
 
447
        if (localaddrs)
 
448
            krb5_free_addresses(localaddrs);
 
449
        return(SendConnSetup(client, "Krb5: neither srvcreds nor ktname set"));
 
450
    }
 
451
    if (localaddrs)
 
452
        krb5_free_addresses(localaddrs);
 
453
    if (rcache)
 
454
    {
 
455
        if (retval2 = krb5_rc_close(rcache))
 
456
        {
 
457
            strcpy(kerror, "krb5_rc_close failed (2): ");
 
458
            strncat(kerror, error_message(retval2), 230);
 
459
            return(SendConnSetup(client, kerror));
 
460
        }
 
461
        free(rcache);
 
462
    }
 
463
    if (retval)
 
464
    {
 
465
        strcpy(kerror, "Krb5: Bad application request: ");
 
466
        strncat(kerror, error_message(retval), 224);
 
467
        return(SendConnSetup(client, kerror));
 
468
    }
 
469
    cprinc = authdat->ticket->enc_part2->client;
 
470
    skey = authdat->ticket->enc_part2->session;
 
471
    if (XauKrb5Encode(cprinc, &buf))
 
472
    {
 
473
        krb5_free_tkt_authent(authdat);
 
474
        return(SendConnSetup(client, "XauKrb5Encode bombed"));
 
475
    }
 
476
    /*
 
477
     * Now check to see if the principal we got is one that we want to let in
 
478
     */
 
479
    if (ForEachHostInFamily(FamilyKrb5Principal, k5_cmpenc, (pointer)&buf))
 
480
    {
 
481
        free(buf.data);
 
482
        /*
 
483
         * The following deals with sending an ap_rep to the client to
 
484
         * achieve mutual authentication.  The client sends back a stage 3
 
485
         * packet if all is ok.
 
486
         */
 
487
        if (authdat->ap_options | AP_OPTS_MUTUAL_REQUIRED)
 
488
        {
 
489
            /*
 
490
             * stage 2: send ap_rep to client
 
491
             */
 
492
            if (retval = krb5_us_timeofday(&ctime, &cusec))
 
493
            {
 
494
                krb5_free_tkt_authent(authdat);
 
495
                strcpy(kerror, "error in krb5_us_timeofday: ");
 
496
                strncat(kerror, error_message(retval), 234);
 
497
                return(SendConnSetup(client, kerror));
 
498
            }
 
499
            rep.ctime = ctime;
 
500
            rep.cusec = cusec;
 
501
            rep.subkey = NULL;
 
502
            rep.seq_number = 0;
 
503
            if (retval = krb5_mk_rep(&rep, skey, &buf))
 
504
            {
 
505
                krb5_free_tkt_authent(authdat);
 
506
                strcpy(kerror, "error in krb5_mk_rep: ");
 
507
                strncat(kerror, error_message(retval), 238);
 
508
                return(SendConnSetup(client, kerror));
 
509
            }
 
510
            prefix.reqType = 2; /* opcode = authenticate */
 
511
            prefix.data = 2;    /* stage = 2 */
 
512
            prefix.length = (buf.length + sz_xReq + 3) >> 2;
 
513
            if (client->swapped)
 
514
            {
 
515
                swaps(&prefix.length, n);
 
516
            }
 
517
            WriteToClient(client, sz_xReq, (char *)&prefix);
 
518
            WriteToClient(client, buf.length, buf.data);
 
519
            free(buf.data);
 
520
            krb5_free_tkt_authent(authdat);
 
521
            ((OsCommPtr)client->osPrivate)->authstate.stageno = 3; /* expect stage3 packet */
 
522
            return(Success);
 
523
        }
 
524
        else
 
525
        {
 
526
            free(buf.data);
 
527
            krb5_free_tkt_authent(authdat);
 
528
            return(SendConnSetup(client, NULL)); /* success! */
 
529
        }
 
530
    }
 
531
    else
 
532
    {
 
533
        char *kname;
 
534
        
 
535
        krb5_free_tkt_authent(authdat);
 
536
        free(buf.data);
 
537
        retval = krb5_unparse_name(cprinc, &kname);
 
538
        if (retval == 0)
 
539
        {
 
540
            sprintf(kerror, "Principal \"%s\" is not authorized to connect",
 
541
                    kname);
 
542
            if (kname)
 
543
                free(kname);
 
544
            return(SendConnSetup(client, kerror));
 
545
        }
 
546
        else
 
547
            return(SendConnSetup(client,"Principal is not authorized to connect to Server"));
 
548
    }
 
549
}
 
550
 
 
551
/*
 
552
 * k5_stage3:
 
553
 *
 
554
 * Get the short ack packet from the client.  This packet can conceivably
 
555
 * be expanded to allow for switching on end-to-end encryption.
 
556
 *
 
557
 * stage3 packet format:
 
558
 *
 
559
 * CARD8        reqType = 3
 
560
 * CARD8        data    = ignored (for now)
 
561
 * CARD16       length  = should be zero
 
562
 */
 
563
int k5_stage3(client)
 
564
    register ClientPtr client;
 
565
{
 
566
    REQUEST(xReq);
 
567
 
 
568
    if (((OsCommPtr)client->osPrivate)->authstate.stageno != 3)
 
569
    {
 
570
        return(SendConnSetup(client, "expected Krb5 stage3 packet"));
 
571
    }
 
572
    else
 
573
        return(SendConnSetup(client, NULL)); /* success! */
 
574
}
 
575
 
 
576
k5_bad(client)
 
577
    register ClientPtr client;
 
578
{
 
579
    if (((OsCommPtr)client->osPrivate)->authstate.srvcreds)
 
580
        krb5_free_creds((krb5_creds *)((OsCommPtr)client->osPrivate)->authstate.srvcreds);
 
581
    sprintf(kerror, "unrecognized Krb5 auth packet %d, expecting %d",
 
582
            ((xReq *)client->requestBuffer)->reqType,
 
583
            ((OsCommPtr)client->osPrivate)->authstate.stageno);
 
584
    return(SendConnSetup(client, kerror));
 
585
}
 
586
 
 
587
/*
 
588
 * K5Add:
 
589
 *
 
590
 * Takes the name of a credentials cache and resolves it.  Also adds the
 
591
 * primary principal of the ccache to the acl.
 
592
 *
 
593
 * Now will also take a service name.
 
594
 */
 
595
int K5Add(data_length, data, id)
 
596
    unsigned short data_length;
 
597
    char *data;
 
598
    XID id;
 
599
{
 
600
    krb5_principal princ;
 
601
    krb5_error_code retval;
 
602
    krb5_keytab_entry tmp_entry;
 
603
    krb5_keytab keytab;
 
604
    krb5_kvno kvno = 0;
 
605
    krb5_ccache cc;
 
606
    char *nbuf, *cp;
 
607
    krb5_data kbuf;
 
608
    int i, ktlen;
 
609
    
 
610
    krb5_init_ets();            /* can't think of a better place to put it */
 
611
    krb5_id = ~0L;
 
612
    if (data_length < 3)
 
613
        return 0;
 
614
    if ((nbuf = (char *)malloc(data_length - 2)) == NULL)
 
615
        return 0;
 
616
    memcpy(nbuf, data + 3, data_length - 3);
 
617
    nbuf[data_length - 3] = '\0';
 
618
    if (ccname)
 
619
    {
 
620
        free(ccname);
 
621
        ccname = NULL;
 
622
    }
 
623
    if (srvname)
 
624
    {
 
625
        krb5_free_principal(srvname);
 
626
        srvname = NULL;
 
627
    }
 
628
    if (ktname)
 
629
    {
 
630
        free(ktname);
 
631
        ktname = NULL;
 
632
    }
 
633
    if (!strncmp(data, "UU:", 3))
 
634
    {
 
635
        if (retval = krb5_cc_resolve(nbuf, &cc))
 
636
        {
 
637
            ErrorF("K5Add: krb5_cc_resolve of \"%s\" failed: %s\n",
 
638
                   nbuf, error_message(retval));
 
639
            free(nbuf);
 
640
            return 0;
 
641
        }
 
642
        if (cc && !(retval = krb5_cc_get_principal(cc, &princ)))
 
643
        {
 
644
            if (XauKrb5Encode(princ, &kbuf))
 
645
            {
 
646
                free(nbuf);
 
647
                krb5_free_principal(princ);
 
648
                krb5_cc_close(cc);
 
649
                return 0;
 
650
            }
 
651
            if (krb5_cc_close(cc))
 
652
                return 0;
 
653
            AddHost(NULL, FamilyKrb5Principal, kbuf.length, kbuf.data);
 
654
            krb5_free_principal(princ);
 
655
            free(kbuf.data);
 
656
            ccname = nbuf;
 
657
            krb5_id = id;
 
658
            return 1;
 
659
        }
 
660
        else
 
661
        {
 
662
            ErrorF("K5Add: getting principal from cache \"%s\" failed: %s\n",
 
663
                   nbuf, error_message(retval));
 
664
        }
 
665
    }
 
666
    else if (!strncmp(data, "CS:", 3))
 
667
    {
 
668
        if ((cp = strchr(nbuf, ',')) == NULL)
 
669
        {
 
670
            free(nbuf);
 
671
            return 0;
 
672
        }
 
673
        *cp = '\0';             /* gross but it works :-) */
 
674
        ktlen = strlen(cp + 1);
 
675
        if ((ktname = (char *)malloc(ktlen + 1)) == NULL)
 
676
        {
 
677
            free(nbuf);
 
678
            return 0;
 
679
        }
 
680
        strcpy(ktname, cp + 1);
 
681
        retval = krb5_sname_to_principal(NULL, /* NULL for hostname uses
 
682
                                                  local host name*/
 
683
                                         nbuf, KRB5_NT_SRV_HST,
 
684
                                         &srvname);
 
685
        free(nbuf);
 
686
        if (retval)
 
687
        {
 
688
            free(ktname);
 
689
            ktname = NULL;
 
690
            return 0;
 
691
        }
 
692
        if (retval = krb5_kt_resolve(ktname, &keytab))
 
693
        {
 
694
            free(ktname);
 
695
            ktname = NULL;
 
696
            krb5_free_principal(srvname);
 
697
            srvname = NULL;
 
698
            return 0;
 
699
        }
 
700
        retval = krb5_kt_get_entry(keytab, srvname, kvno, &tmp_entry);
 
701
        krb5_kt_free_entry(&tmp_entry);
 
702
        if (retval)
 
703
        {
 
704
            free(ktname);
 
705
            ktname = NULL;
 
706
            krb5_free_principal(srvname);
 
707
            srvname = NULL;
 
708
            return 0;
 
709
        }
 
710
        if (XauKrb5Encode(srvname, &kbuf))
 
711
        {
 
712
            free(ktname);
 
713
            ktname = NULL;
 
714
            krb5_free_principal(srvname);
 
715
            srvname = NULL;
 
716
            return 0;
 
717
        }
 
718
        AddHost(NULL, FamilyKrb5Principal, kbuf.length, kbuf.data);
 
719
        krb5_id = id;
 
720
        return 1;
 
721
    }
 
722
    else
 
723
    {
 
724
        ErrorF("K5Add: credentials cache name \"%.*s\" in auth file: unknown type\n",
 
725
               data_length, data);
 
726
    }
 
727
    return 0;
 
728
}
 
729
 
 
730
/*
 
731
 * K5Reset:
 
732
 *
 
733
 * Reset krb5_id, also nuke the current principal from the acl.
 
734
 */
 
735
int K5Reset()
 
736
{
 
737
    krb5_principal princ;
 
738
    krb5_error_code retval;
 
739
    krb5_ccache cc;
 
740
    krb5_data kbuf;
 
741
    int i;
 
742
    
 
743
    if (ccname)
 
744
    {
 
745
        if (retval = krb5_cc_resolve(ccname, &cc))
 
746
        {
 
747
            free(ccname);
 
748
            ccname = NULL;
 
749
        }
 
750
        if (cc && !(retval = krb5_cc_get_principal(cc, &princ)))
 
751
        {
 
752
            if (XauKrb5Encode(princ, &kbuf))
 
753
                return 1;
 
754
            RemoveHost(NULL, FamilyKrb5Principal, kbuf.length, kbuf.data);
 
755
            krb5_free_principal(princ);
 
756
            free(kbuf.data);
 
757
            if (krb5_cc_close(cc))
 
758
                return 1;
 
759
            free(ccname);
 
760
            ccname = NULL;
 
761
        }
 
762
    }
 
763
    if (srvname)
 
764
    {
 
765
        if (XauKrb5Encode(srvname, &kbuf))
 
766
            return 1;
 
767
        RemoveHost(NULL, FamilyKrb5Principal, kbuf.length, kbuf.data);
 
768
        krb5_free_principal(srvname);
 
769
        free(kbuf.data);
 
770
        srvname = NULL;
 
771
    }
 
772
    if (ktname)
 
773
    {
 
774
        free(ktname);
 
775
        ktname = NULL;
 
776
    }
 
777
    krb5_id = ~0L;
 
778
    return 0;
 
779
}
 
780
 
 
781
XID K5ToID(data_length, data)
 
782
    unsigned short data_length;
 
783
    char *data;
 
784
{
 
785
    return krb5_id;
 
786
}
 
787
 
 
788
int K5FromID(id, data_lenp, datap)
 
789
    XID id;
 
790
    unsigned short *data_lenp;
 
791
    char **datap;
 
792
{
 
793
    return 0;
 
794
}
 
795
 
 
796
int K5Remove(data_length, data)
 
797
    unsigned short data_length;
 
798
    char *data;
 
799
{
 
800
    return 0;
 
801
}