The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
krb5.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 55e99b4d892d1001dcd58d799411bdd26833e2ad $
19  * @file krb5.h
20  * @brief Context management functions for rlm_krb5
21  *
22  * @copyright 2013 The FreeRADIUS server project
23  * @copyright 2013 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24  */
25 RCSID("$Id: 55e99b4d892d1001dcd58d799411bdd26833e2ad $")
26 
27 #define LOG_PREFIX inst->name
28 
29 #include <freeradius-devel/util/debug.h>
30 #include <freeradius-devel/server/base.h>
31 #include "krb5.h"
32 
33 #ifdef HAVE_KRB5_GET_ERROR_MESSAGE
34 # define KRB5_STRERROR_BUFSIZE (2048)
35 
36 static _Thread_local char *krb5_error_buffer;
37 
38 /*
39  * Explicitly cleanup the memory allocated to the error buffer.
40  */
41 static int _krb5_logging_free(void *arg)
42 {
43  return talloc_free(arg);
44 }
45 
46 char const *rlm_krb5_error(rlm_krb5_t const *inst, krb5_context context, krb5_error_code code)
47 {
48  char const *msg;
49  char *buffer;
50 
51  if (!fr_cond_assert(inst)) return NULL;
52 
53  buffer = krb5_error_buffer;
54  if (!buffer) {
55  buffer = talloc_array(NULL, char, KRB5_STRERROR_BUFSIZE);
56  if (!buffer) {
57  ERROR("Failed allocating memory for krb5 error buffer");
58  return NULL;
59  }
60 
61  fr_atexit_thread_local(krb5_error_buffer, _krb5_logging_free, buffer);
62  }
63 
64  msg = krb5_get_error_message(context, code);
65  if (msg) {
66  strlcpy(buffer, msg, KRB5_STRERROR_BUFSIZE);
67 # ifdef HAVE_KRB5_FREE_ERROR_MESSAGE
68  krb5_free_error_message(context, msg);
69 # elif defined(HAVE_KRB5_FREE_ERROR_STRING)
70  krb5_free_error_string(context, UNCONST(char *, msg));
71 # else
72 # error "No way to free error strings, missing krb5_free_error_message() and krb5_free_error_string()"
73 # endif
74  } else {
75  strlcpy(buffer, "Unknown error", KRB5_STRERROR_BUFSIZE);
76  }
77 
78  return buffer;
79 }
80 #endif
81 
82 /** Frees libkrb5 resources associated with the handle
83  *
84  * Must not be called directly.
85  *
86  * @param conn to free.
87  * @return 0 (always indicates success).
88  */
89 static int _mod_conn_free(rlm_krb5_handle_t *conn) {
90  krb5_free_context(conn->context);
91 
92  if (conn->keytab) krb5_kt_close(conn->context, conn->keytab);
93 
94 #ifdef HEIMDAL_KRB5
95  if (conn->ccache) krb5_cc_destroy(conn->context, conn->ccache);
96 #endif
97 
98  return 0;
99 }
100 
101 /** Create and return a new connection
102  *
103  * libkrb5(s) can talk to the KDC over TCP. Were assuming something sane is implemented
104  * by libkrb5 and that it does connection caching associated with contexts, so it's
105  * worth using a connection pool to preserve connections when workers die.
106  */
107 void *krb5_mod_conn_create(TALLOC_CTX *ctx, void *instance, UNUSED fr_time_delta_t timeout)
108 {
110  rlm_krb5_handle_t *conn;
111  krb5_error_code ret;
112 
113  MEM(conn = talloc_zero(ctx, rlm_krb5_handle_t));
114  ret = krb5_init_context(&conn->context);
115  if (ret) {
116  ERROR("Context initialisation failed: %s", rlm_krb5_error(inst, NULL, ret));
117 
118  return NULL;
119  }
120  talloc_set_destructor(conn, _mod_conn_free);
121 
122  ret = inst->keytabname ?
123  krb5_kt_resolve(conn->context, inst->keytabname, &conn->keytab) :
124  krb5_kt_default(conn->context, &conn->keytab);
125  if (ret) {
126  ERROR("Resolving keytab failed: %s", rlm_krb5_error(inst, conn->context, ret));
127 
128  goto cleanup;
129  }
130 
131 #ifdef HEIMDAL_KRB5
132  ret = krb5_cc_new_unique(conn->context, "MEMORY", NULL, &conn->ccache);
133  if (ret) {
134  ERROR("Credential cache creation failed: %s", rlm_krb5_error(inst, conn->context, ret));
135 
136  return NULL;
137  }
138 
139  krb5_verify_opt_init(&conn->options);
140  krb5_verify_opt_set_ccache(&conn->options, conn->ccache);
141 
142  krb5_verify_opt_set_keytab(&conn->options, conn->keytab);
143  krb5_verify_opt_set_secure(&conn->options, true);
144 
145  if (inst->service) krb5_verify_opt_set_service(&conn->options, inst->service);
146 #else
147  krb5_verify_init_creds_opt_set_ap_req_nofail(inst->vic_options, true);
148 #endif
149  return conn;
150 
151 cleanup:
152  talloc_free(conn);
153  return NULL;
154 }
static int const char char buffer[256]
Definition: acutest.h:574
log_entry msg
Definition: acutest.h:794
#define fr_atexit_thread_local(_name, _free, _uctx)
Definition: atexit.h:221
static int context
Definition: radmin.c:71
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition: build.h:165
#define RCSID(id)
Definition: build.h:444
#define UNUSED
Definition: build.h:313
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:137
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
static fr_time_delta_t timeout
Definition: dhcpclient.c:54
void * krb5_mod_conn_create(TALLOC_CTX *ctx, void *instance, UNUSED fr_time_delta_t timeout)
Create and return a new connection.
Definition: krb5.c:107
static int _mod_conn_free(rlm_krb5_handle_t *conn)
Frees libkrb5 resources associated with the handle.
Definition: krb5.c:89
Context management functions for rlm_krb5.
krb5_keytab keytab
Definition: krb5.h:38
#define rlm_krb5_error(_x, _y, _z)
Definition: krb5.h:89
krb5_context context
Definition: krb5.h:37
Instance configuration for rlm_krb5.
Definition: krb5.h:50
talloc_free(reap)
static bool cleanup
Definition: radsniff.c:60
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:34
#define talloc_get_type_abort_const
Definition: talloc.h:270
A time delta, a difference in time measured in nanoseconds.
Definition: time.h:80