2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
10 * Copyright 1990,2001 by the Massachusetts Institute of Technology.
12 * Export of this software from the United States of America may
13 * require a specific license from the United States Government.
14 * It is the responsibility of any person or organization contemplating
15 * export to obtain such a license before exporting.
17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18 * distribute this software and its documentation for any purpose and
19 * without fee is hereby granted, provided that the above copyright
20 * notice appear in all copies and that both that copyright notice and
21 * this permission notice appear in supporting documentation, and that
22 * the name of M.I.T. not be used in advertising or publicity pertaining
23 * to distribution of the software without specific, written prior
24 * permission. Furthermore if you modify this software you must label
25 * your software as modified software and not distribute it in such a
26 * fashion that it might be confused with the original M.I.T. software.
27 * M.I.T. makes no representations about the suitability of
28 * this software for any purpose. It is provided "as is" without express
29 * or implied warranty.
32 * Main procedure body for the KDC server process.
44 #include "adm_proto.h"
51 #ifdef HAVE_NETINET_IN_H
52 #include <netinet/in.h>
55 #ifdef KRB5_KRB4_COMPAT
59 #if defined(NEED_DAEMON_PROTO)
60 extern int daemon(int, int);
65 krb5_sigtype
request_exit (int);
66 krb5_sigtype
request_hup (int);
68 void setup_signal_handlers (void);
70 krb5_error_code
setup_sam (void);
72 void initialize_realms (krb5_context
, int, char **);
74 void finish_realms (char *);
76 static int nofork
= 0;
77 static int rkey_init_done
= 0;
79 /* Solaris Kerberos: global here that other functions access */
80 int max_tcp_data_connections
;
83 static struct sigaction s_action
;
84 #endif /* POSIX_SIGNALS */
86 #define KRB5_KDC_MAX_REALMS 32
89 * Find the realm entry for a given realm.
92 find_realm_data(char *rname
, krb5_ui_4 rsize
)
95 for (i
=0; i
<kdc_numrealms
; i
++) {
96 if ((rsize
== strlen(kdc_realmlist
[i
]->realm_name
)) &&
97 !strncmp(rname
, kdc_realmlist
[i
]->realm_name
, rsize
))
98 return(kdc_realmlist
[i
]);
100 return((kdc_realm_t
*) NULL
);
104 setup_server_realm(krb5_principal sprinc
)
106 krb5_error_code kret
;
107 kdc_realm_t
*newrealm
;
110 if (kdc_numrealms
> 1) {
111 if (!(newrealm
= find_realm_data(sprinc
->realm
.data
,
112 (krb5_ui_4
) sprinc
->realm
.length
)))
115 kdc_active_realm
= newrealm
;
118 kdc_active_realm
= kdc_realmlist
[0];
123 finish_realm(kdc_realm_t
*rdp
)
125 if (rdp
->realm_dbname
)
126 free(rdp
->realm_dbname
);
127 if (rdp
->realm_mpname
)
128 free(rdp
->realm_mpname
);
129 if (rdp
->realm_stash
)
130 free(rdp
->realm_stash
);
131 if (rdp
->realm_ports
)
132 free(rdp
->realm_ports
);
133 if (rdp
->realm_tcp_ports
)
134 free(rdp
->realm_tcp_ports
);
135 if (rdp
->realm_keytab
)
136 krb5_kt_close(rdp
->realm_context
, rdp
->realm_keytab
);
137 if (rdp
->realm_context
) {
138 if (rdp
->realm_mprinc
)
139 krb5_free_principal(rdp
->realm_context
, rdp
->realm_mprinc
);
140 if (rdp
->realm_mkey
.length
&& rdp
->realm_mkey
.contents
) {
141 memset(rdp
->realm_mkey
.contents
, 0, rdp
->realm_mkey
.length
);
142 free(rdp
->realm_mkey
.contents
);
144 krb5_db_fini(rdp
->realm_context
);
145 if (rdp
->realm_tgsprinc
)
146 krb5_free_principal(rdp
->realm_context
, rdp
->realm_tgsprinc
);
147 krb5_free_context(rdp
->realm_context
);
149 memset((char *) rdp
, 0, sizeof(*rdp
));
154 * Initialize a realm control structure from the alternate profile or from
155 * the specified defaults.
157 * After we're complete here, the essence of the realm is embodied in the
158 * realm data and we should be all set to begin operation for that realm.
160 static krb5_error_code
161 init_realm(krb5_context kcontext
, char *progname
, kdc_realm_t
*rdp
, char *realm
,
162 char *def_mpname
, krb5_enctype def_enctype
, char *def_udp_ports
,
163 char *def_tcp_ports
, krb5_boolean def_manual
, char **db_args
)
165 krb5_error_code kret
;
167 krb5_realm_params
*rparams
;
169 memset((char *) rdp
, 0, sizeof(kdc_realm_t
));
175 rdp
->realm_name
= realm
;
176 kret
= krb5int_init_context_kdc(&rdp
->realm_context
);
178 com_err(progname
, kret
, gettext("while getting context for realm %s"),
185 * Set the current context to that of the realm being init'ed
187 krb5_klog_set_context(rdp
->realm_context
);
189 kret
= krb5_read_realm_params(rdp
->realm_context
, rdp
->realm_name
,
192 com_err(progname
, kret
, gettext("while reading realm parameters"));
196 /* Handle profile file name */
197 if (rparams
&& rparams
->realm_profile
)
198 rdp
->realm_profile
= strdup(rparams
->realm_profile
);
200 /* Handle master key name */
201 if (rparams
&& rparams
->realm_mkey_name
)
202 rdp
->realm_mpname
= strdup(rparams
->realm_mkey_name
);
204 rdp
->realm_mpname
= (def_mpname
) ? strdup(def_mpname
) :
205 strdup(KRB5_KDB_M_NAME
);
207 /* Handle KDC ports */
208 if (rparams
&& rparams
->realm_kdc_ports
)
209 rdp
->realm_ports
= strdup(rparams
->realm_kdc_ports
);
211 rdp
->realm_ports
= strdup(def_udp_ports
);
212 if (rparams
&& rparams
->realm_kdc_tcp_ports
)
213 rdp
->realm_tcp_ports
= strdup(rparams
->realm_kdc_tcp_ports
);
215 rdp
->realm_tcp_ports
= strdup(def_tcp_ports
);
217 /* Handle stash file */
218 if (rparams
&& rparams
->realm_stash_file
) {
219 rdp
->realm_stash
= strdup(rparams
->realm_stash_file
);
224 /* Handle master key type */
225 if (rparams
&& rparams
->realm_enctype_valid
)
226 rdp
->realm_mkey
.enctype
= (krb5_enctype
) rparams
->realm_enctype
;
228 rdp
->realm_mkey
.enctype
= manual
? def_enctype
: ENCTYPE_UNKNOWN
;
230 /* Handle reject-bad-transit flag */
231 if (rparams
&& rparams
->realm_reject_bad_transit_valid
)
232 rdp
->realm_reject_bad_transit
= rparams
->realm_reject_bad_transit
;
234 rdp
->realm_reject_bad_transit
= 1;
236 /* Handle ticket maximum life */
237 rdp
->realm_maxlife
= (rparams
&& rparams
->realm_max_life_valid
) ?
238 rparams
->realm_max_life
: KRB5_KDB_MAX_LIFE
;
240 /* Handle ticket renewable maximum life */
241 rdp
->realm_maxrlife
= (rparams
&& rparams
->realm_max_rlife_valid
) ?
242 rparams
->realm_max_rlife
: KRB5_KDB_MAX_RLIFE
;
245 krb5_free_realm_params(rdp
->realm_context
, rparams
);
248 * We've got our parameters, now go and setup our realm context.
251 /* Set the default realm of this context */
252 if ((kret
= krb5_set_default_realm(rdp
->realm_context
, realm
))) {
253 com_err(progname
, kret
, gettext("while setting default realm to %s"),
258 /* first open the database before doing anything */
259 #ifdef KRBCONF_KDC_MODIFIES_KDB
260 if ((kret
= krb5_db_open(rdp
->realm_context
, db_args
,
261 KRB5_KDB_OPEN_RW
| KRB5_KDB_SRV_TYPE_KDC
))) {
263 if ((kret
= krb5_db_open(rdp
->realm_context
, db_args
,
264 KRB5_KDB_OPEN_RO
| KRB5_KDB_SRV_TYPE_KDC
))) {
268 * Make sure that error messages are printed using gettext
270 com_err(progname
, kret
,
271 gettext("while initializing database for realm %s"), realm
);
275 /* Assemble and parse the master key name */
276 if ((kret
= krb5_db_setup_mkey_name(rdp
->realm_context
, rdp
->realm_mpname
,
277 rdp
->realm_name
, (char **) NULL
,
278 &rdp
->realm_mprinc
))) {
279 com_err(progname
, kret
,
280 gettext("while setting up master key name %s for realm %s"),
281 rdp
->realm_mpname
, realm
);
286 * Get the master key.
288 if ((kret
= krb5_db_fetch_mkey(rdp
->realm_context
, rdp
->realm_mprinc
,
289 rdp
->realm_mkey
.enctype
, manual
,
290 FALSE
, rdp
->realm_stash
,
291 0, &rdp
->realm_mkey
))) {
292 com_err(progname
, kret
,
293 gettext("while fetching master key %s for realm %s"),
294 rdp
->realm_mpname
, realm
);
298 /* Verify the master key */
299 if ((kret
= krb5_db_verify_master_key(rdp
->realm_context
,
301 &rdp
->realm_mkey
))) {
302 com_err(progname
, kret
,
303 gettext("while verifying master key for realm %s"),
308 if ((kret
= krb5_db_set_mkey(rdp
->realm_context
, &rdp
->realm_mkey
))) {
309 com_err(progname
, kret
,
310 gettext("while processing master key for realm %s"),
315 /* Set up the keytab */
316 if ((kret
= krb5_ktkdb_resolve(rdp
->realm_context
, NULL
,
317 &rdp
->realm_keytab
))) {
318 com_err(progname
, kret
,
319 gettext("while resolving kdb keytab for realm %s"),
324 /* Preformat the TGS name */
325 if ((kret
= krb5_build_principal(rdp
->realm_context
, &rdp
->realm_tgsprinc
,
326 strlen(realm
), realm
, KRB5_TGS_NAME
,
327 realm
, (char *) NULL
))) {
328 com_err(progname
, kret
,
329 gettext("while building TGS name for realm %s"),
334 if (!rkey_init_done
) {
336 #ifdef KRB5_KRB4_COMPAT
337 krb5_keyblock temp_key
;
340 * If all that worked, then initialize the random key
344 seed
.length
= rdp
->realm_mkey
.length
;
345 seed
.data
= (char *)rdp
->realm_mkey
.contents
;
346 /* SUNW14resync - XXX */
348 if ((kret
= krb5_c_random_add_entropy(rdp
->realm_context
,
349 KRB5_C_RANDSOURCE_TRUSTEDPARTY
, &seed
)))
353 #ifdef KRB5_KRB4_COMPAT
354 if ((kret
= krb5_c_make_random_key(rdp
->realm_context
,
355 ENCTYPE_DES_CBC_CRC
, &temp_key
))) {
356 com_err(progname
, kret
,
357 "while initializing V4 random key generator");
361 (void) des_init_random_number_generator(temp_key
.contents
);
362 krb5_free_keyblock_contents(rdp
->realm_context
, &temp_key
);
368 * If we choked, then clean up any dirt we may have dropped on the floor.
377 * Set the current context back to the general context
379 krb5_klog_set_context(kcontext
);
385 request_exit(int signo
)
387 signal_requests_exit
= 1;
397 request_hup(int signo
)
399 signal_requests_hup
= 1;
409 setup_signal_handlers(void)
412 (void) sigemptyset(&s_action
.sa_mask
);
413 s_action
.sa_flags
= 0;
414 s_action
.sa_handler
= request_exit
;
415 (void) sigaction(SIGINT
, &s_action
, (struct sigaction
*) NULL
);
416 (void) sigaction(SIGTERM
, &s_action
, (struct sigaction
*) NULL
);
417 s_action
.sa_handler
= request_hup
;
418 (void) sigaction(SIGHUP
, &s_action
, (struct sigaction
*) NULL
);
419 s_action
.sa_handler
= SIG_IGN
;
420 (void) sigaction(SIGPIPE
, &s_action
, (struct sigaction
*) NULL
);
421 #else /* POSIX_SIGNALS */
422 signal(SIGINT
, request_exit
);
423 signal(SIGTERM
, request_exit
);
424 signal(SIGHUP
, request_hup
);
425 signal(SIGPIPE
, SIG_IGN
);
426 #endif /* POSIX_SIGNALS */
434 return krb5_c_make_random_key(kdc_context
, ENCTYPE_DES_CBC_MD5
, &psr_key
);
440 fprintf(stderr
, gettext("usage: %s [-d dbpathname] [-r dbrealmname] [-R replaycachename ]\n\t[-m] [-k masterenctype] [-M masterkeyname] [-p port] [-n]\n"), name
);
441 fprintf(stderr
, "usage: %s [-x db_args]* [-d dbpathname] [-r dbrealmname] [-R replaycachename ]\n\t[-m] [-k masterenctype] [-M masterkeyname] [-p port] [-X] [-n]\n"
442 "\nwhere,\n\t[-x db_args]* - any number of database specific arguments.\n"
443 "\t\t\tLook at each database documentation for supported arguments\n",
449 initialize_realms(krb5_context kcontext
, int argc
, char **argv
)
452 char *db_name
= (char *) NULL
;
453 char *mkey_name
= (char *) NULL
;
454 char *rcname
= KDCRCACHE
;
456 krb5_error_code retval
;
457 krb5_enctype menctype
= ENCTYPE_UNKNOWN
;
459 krb5_boolean manual
= FALSE
;
460 char *default_udp_ports
= 0;
461 char *default_tcp_ports
= 0;
463 const char *hierarchy
[3];
464 char **db_args
= NULL
;
465 int db_args_size
= 0;
467 #ifdef KRB5_KRB4_COMPAT
472 if (!krb5_aprof_init(DEFAULT_KDC_PROFILE
, KDC_PROFILE_ENV
, &aprof
)) {
473 hierarchy
[0] = "kdcdefaults";
474 hierarchy
[1] = "kdc_ports";
475 hierarchy
[2] = (char *) NULL
;
476 if (krb5_aprof_get_string(aprof
, hierarchy
, TRUE
, &default_udp_ports
))
477 default_udp_ports
= 0;
478 hierarchy
[1] = "kdc_tcp_ports";
479 if (krb5_aprof_get_string(aprof
, hierarchy
, TRUE
, &default_tcp_ports
))
480 default_tcp_ports
= 0;
481 hierarchy
[1] = "kdc_max_tcp_connections";
482 if (krb5_aprof_get_int32(aprof
, hierarchy
, TRUE
,
483 &max_tcp_data_connections
)) {
484 max_tcp_data_connections
= DEFAULT_KDC_TCP_CONNECTIONS
;
485 } else if (max_tcp_data_connections
< MIN_KDC_TCP_CONNECTIONS
) {
486 max_tcp_data_connections
= DEFAULT_KDC_TCP_CONNECTIONS
;
488 #ifdef KRB5_KRB4_COMPAT
489 hierarchy
[1] = "v4_mode";
490 if (krb5_aprof_get_string(aprof
, hierarchy
, TRUE
, &v4mode
))
493 /* aprof_init can return 0 with aprof == NULL */
495 krb5_aprof_finish(aprof
);
497 if (default_udp_ports
== 0)
498 default_udp_ports
= strdup(DEFAULT_KDC_UDP_PORTLIST
);
499 if (default_tcp_ports
== 0)
500 default_tcp_ports
= strdup(DEFAULT_KDC_TCP_PORTLIST
);
502 * Loop through the option list. Each time we encounter a realm name,
503 * use the previously scanned options to fill in for defaults.
505 while ((c
= getopt(argc
, argv
, "x:r:d:mM:k:R:e:p:s:n4:X3")) != -1) {
510 char **temp
= realloc( db_args
, sizeof(char*) * (db_args_size
+1)); /* one for NULL */
513 /* Solaris Kerberos: Keep error messages consistent */
514 com_err(argv
[0], errno
, gettext("while initializing KDC"));
520 db_args
[db_args_size
-1] = optarg
;
521 db_args
[db_args_size
] = NULL
;
524 case 'r': /* realm name for db */
525 if (!find_realm_data(optarg
, (krb5_ui_4
) strlen(optarg
))) {
526 if ((rdatap
= (kdc_realm_t
*) malloc(sizeof(kdc_realm_t
)))) {
527 if ((retval
= init_realm(kcontext
, argv
[0], rdatap
, optarg
,
530 default_tcp_ports
, manual
, db_args
))) {
531 /* Solaris Kerberos: Keep error messages consistent */
532 com_err(argv
[0], retval
, gettext("while initializing realm %s"), optarg
);
535 kdc_realmlist
[kdc_numrealms
] = rdatap
;
537 free(db_args
), db_args
=NULL
, db_args_size
= 0;
541 /* Solaris Kerberos: Keep error messages consistent */
542 com_err(argv
[0], errno
, gettext("while initializing realm %s"), optarg
);
547 case 'd': /* pathname for db */
548 /* now db_name is not a seperate argument. It has to be passed as part of the db_args */
549 if( db_name
== NULL
)
551 db_name
= malloc(sizeof("dbname=") + strlen(optarg
));
552 if( db_name
== NULL
)
554 /* Solaris Kerberos: Keep error messages consistent */
555 com_err(argv
[0], errno
, gettext("while initializing KDC"));
559 sprintf( db_name
, "dbname=%s", optarg
);
564 char **temp
= realloc( db_args
, sizeof(char*) * (db_args_size
+1)); /* one for NULL */
567 /* Solaris Kerberos: Keep error messages consistent */
568 com_err(argv
[0], errno
, gettext("while initializing KDC"));
574 db_args
[db_args_size
-1] = db_name
;
575 db_args
[db_args_size
] = NULL
;
577 case 'm': /* manual type-in of master key */
579 if (menctype
== ENCTYPE_UNKNOWN
)
580 menctype
= ENCTYPE_DES_CBC_CRC
;
582 case 'M': /* master key name in DB */
586 nofork
++; /* don't detach from terminal */
588 case 'k': /* enctype for master key */
589 /* Solaris Kerberos: Keep error messages consistent */
590 if (retval
= krb5_string_to_enctype(optarg
, &menctype
))
591 com_err(argv
[0], retval
,
592 gettext("while converting %s to an enctype"), optarg
);
598 if (default_udp_ports
)
599 free(default_udp_ports
);
600 default_udp_ports
= strdup(optarg
);
602 if (default_tcp_ports
)
603 free(default_tcp_ports
);
604 default_tcp_ports
= strdup(optarg
);
608 #ifdef KRB5_KRB4_COMPAT
611 v4mode
= strdup(optarg
);
615 #ifdef KRB5_KRB4_COMPAT
616 enable_v4_crossrealm(argv
[0]);
626 #ifdef KRB5_KRB4_COMPAT
630 process_v4_mode(argv
[0], v4mode
);
635 * Check to see if we processed any realms.
637 if (kdc_numrealms
== 0) {
638 /* no realm specified, use default realm */
639 if ((retval
= krb5_get_default_realm(kcontext
, &lrealm
))) {
640 com_err(argv
[0], retval
,
641 gettext("while attempting to retrieve default realm"));
642 /* Solaris Kerberos: avoid double logging */
644 fprintf (stderr
, "%s: %s, %s", argv
[0], error_message (retval
),
645 gettext("attempting to retrieve default realm\n"));
649 if ((rdatap
= (kdc_realm_t
*) malloc(sizeof(kdc_realm_t
)))) {
650 if ((retval
= init_realm(kcontext
, argv
[0], rdatap
, lrealm
,
651 mkey_name
, menctype
, default_udp_ports
,
652 default_tcp_ports
, manual
, db_args
))) {
653 /* Solaris Kerberos: Keep error messages consistent */
654 com_err(argv
[0], retval
, gettext("while initializing realm %s"), lrealm
);
657 kdc_realmlist
[0] = rdatap
;
667 * Now handle the replay cache.
669 if ((retval
= kdc_initialize_rcache(kcontext
, rcname
))) {
670 com_err(argv
[0], retval
, gettext("while initializing KDC replay cache '%s'"),
676 /* Ensure that this is set for our first request. */
677 kdc_active_realm
= kdc_realmlist
[0];
679 if (default_udp_ports
)
680 free(default_udp_ports
);
681 if (default_tcp_ports
)
682 free(default_tcp_ports
);
692 finish_realms(char *prog
)
696 for (i
= 0; i
< kdc_numrealms
; i
++) {
697 finish_realm(kdc_realmlist
[i
]);
698 kdc_realmlist
[i
] = 0;
707 initialize database access (fetch master key, open DB)
714 determine packet type, dispatch to handling routine
721 clean up secrets, close db
728 int main(int argc
, char **argv
)
730 krb5_error_code retval
;
731 krb5_context kcontext
;
734 krb5_boolean log_stderr_set
;
736 (void) setlocale(LC_ALL
, "");
738 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
739 #define TEXT_DOMAIN "KRB5KDC_TEST" /* Use this only if it weren't */
742 (void) textdomain(TEXT_DOMAIN
);
744 if (strrchr(argv
[0], '/'))
745 argv
[0] = strrchr(argv
[0], '/')+1;
747 if (!(kdc_realmlist
= (kdc_realm_t
**) malloc(sizeof(kdc_realm_t
*) *
748 KRB5_KDC_MAX_REALMS
))) {
749 fprintf(stderr
, gettext("%s: cannot get memory for realm list\n"), argv
[0]);
752 memset((char *) kdc_realmlist
, 0,
753 (size_t) (sizeof(kdc_realm_t
*) * KRB5_KDC_MAX_REALMS
));
756 * A note about Kerberos contexts: This context, "kcontext", is used
757 * for the KDC operations, i.e. setup, network connection and error
758 * reporting. The per-realm operations use the "realm_context"
759 * associated with each realm.
761 retval
= krb5int_init_context_kdc(&kcontext
);
763 com_err(argv
[0], retval
, gettext("while initializing krb5"));
766 krb5_klog_init(kcontext
, "kdc", argv
[0], 1);
770 * In the early stages of krb5kdc it is desirable to log error messages
771 * to stderr as well as any other logging locations specified in config
774 log_stderr_set
= krb5_klog_logging_to_stderr();
775 if (log_stderr_set
!= TRUE
) {
776 krb5_klog_add_stderr();
779 /* initialize_kdc5_error_table(); SUNWresync121 XXX */
782 * Scan through the argument list
784 initialize_realms(kcontext
, argc
, argv
);
786 setup_signal_handlers();
788 load_preauth_plugins(kcontext
);
790 retval
= setup_sam();
792 com_err(argv
[0], retval
, gettext("while initializing SAM"));
793 finish_realms(argv
[0]);
797 if ((retval
= setup_network(argv
[0]))) {
798 com_err(argv
[0], retval
, gettext("while initializing network"));
799 finish_realms(argv
[0]);
803 /* Solaris Kerberos: Remove the extra stderr logging */
804 if (log_stderr_set
!= TRUE
)
805 krb5_klog_remove_stderr();
809 * List the logs (FILE, STDERR, etc) which are currently being
810 * logged to and print that to stderr. Useful when trying to
811 * track down a failure via SMF.
813 if (retval
= krb5_klog_list_logs(argv
[0])) {
814 com_err(argv
[0], retval
, gettext("while listing logs"));
815 if (log_stderr_set
!= TRUE
) {
816 fprintf(stderr
, gettext("%s: %s while listing logs\n"),
817 argv
[0], error_message(retval
));
821 if (!nofork
&& daemon(0, 0)) {
822 com_err(argv
[0], errno
, gettext("while detaching from tty"));
823 if (log_stderr_set
!= TRUE
) {
824 fprintf(stderr
, gettext("%s: %s while detaching from tty\n"),
825 argv
[0], strerror(errno
));
827 finish_realms(argv
[0]);
830 if (retval
= krb5_klog_syslog(LOG_INFO
, "commencing operation")) {
831 com_err(argv
[0], retval
, gettext("while logging message"));
835 if ((retval
= listen_and_process(argv
[0]))) {
836 com_err(argv
[0], retval
, gettext("while processing network requests"));
839 if ((retval
= closedown_network(argv
[0]))) {
840 com_err(argv
[0], retval
, gettext("while shutting down network"));
843 krb5_klog_syslog(LOG_INFO
, "shutting down");
844 unload_preauth_plugins(kcontext
);
845 krb5_klog_close(kdc_context
);
846 finish_realms(argv
[0]);
850 (void) krb5_rc_close(kcontext
, kdc_rcache
);
853 kdc_free_lookaside(kcontext
);
855 krb5_free_context(kcontext
);