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