The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rlm_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: 033f6148c216b1211ebc6f88ef4d121c50c44441 $
19  * @file rlm_krb5.c
20  * @brief Authenticate users, retrieving their TGT from a Kerberos V5 TDC.
21  *
22  * @copyright 2000,2006,2012-2013 The FreeRADIUS server project
23  * @copyright 2013 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24  * @copyright 2000 Nathan Neulinger (nneul@umr.edu)
25  * @copyright 2000 Alan DeKok (aland@freeradius.org)
26  */
27 RCSID("$Id: 033f6148c216b1211ebc6f88ef4d121c50c44441 $")
28 
29 #define LOG_PREFIX inst->name
30 
31 #include <freeradius-devel/server/base.h>
32 #include <freeradius-devel/server/module_rlm.h>
33 #include <freeradius-devel/util/debug.h>
34 #include "krb5.h"
35 
36 static const conf_parser_t module_config[] = {
37  { FR_CONF_OFFSET("keytab", rlm_krb5_t, keytabname) },
38  { FR_CONF_OFFSET("service_principal", rlm_krb5_t, service_princ) },
40 };
41 
42 static fr_dict_t const *dict_radius;
43 
46  { .out = &dict_radius, .proto = "radius" },
47  { NULL }
48 };
49 
52 
55  { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
56  { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
57  { NULL }
58 };
59 
60 static int mod_detach(module_detach_ctx_t const *mctx)
61 {
62  rlm_krb5_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_krb5_t);
63 
64 #ifndef HEIMDAL_KRB5
65  talloc_free(inst->vic_options);
66 
67  if (inst->gic_options) krb5_get_init_creds_opt_free(inst->context, inst->gic_options);
68  if (inst->server) krb5_free_principal(inst->context, inst->server);
69 #endif
70 
71  /* Don't free hostname, it's just a pointer into service_princ */
72  talloc_free(inst->service);
73 
74  if (inst->context) krb5_free_context(inst->context);
75 #ifdef KRB5_IS_THREAD_SAFE
76  fr_pool_free(inst->pool);
77 #endif
78 
79  return 0;
80 }
81 
82 static int mod_instantiate(module_inst_ctx_t const *mctx)
83 {
84  rlm_krb5_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_krb5_t);
85  krb5_error_code ret;
86 #ifndef HEIMDAL_KRB5
87  krb5_keytab keytab;
88  char keytab_name[200];
89  char *princ_name;
90 #endif
91 
92 #ifdef HEIMDAL_KRB5
93  DEBUG("Using Heimdal Kerberos library");
94 #else
95  DEBUG("Using MIT Kerberos library");
96 #endif
97 
98 
99  if (!krb5_is_thread_safe()) {
100 /*
101  * rlm_krb5 was built as threadsafe
102  */
103 #ifdef KRB5_IS_THREAD_SAFE
104  ERROR("Build time libkrb5 was threadsafe, but run time library claims not to be");
105  ERROR("Modify runtime linker path (LD_LIBRARY_PATH on most systems), to prefer threadsafe libkrb5");
106  return -1;
107 /*
108  * rlm_krb5 was not built as threadsafe
109  */
110 #else
111  fr_log(&default_log, L_WARN, __FILE__, __LINE__,
112  "libkrb5 is not threadsafe, recompile it with thread support enabled ("
113 # ifdef HEIMDAL_KRB5
114  "--enable-pthread-support"
115 # else
116  "--disable-thread-support=no"
117 # endif
118  ")");
119  WARN("rlm_krb5 will run in single threaded mode, performance may be degraded");
120  } else {
121  WARN("Build time libkrb5 was not threadsafe, but run time library claims to be");
122  WARN("Reconfigure and recompile rlm_krb5 to enable thread support");
123 #endif
124  }
125 
126  ret = krb5_init_context(&inst->context);
127  if (ret) {
128  ERROR("Context initialisation failed: %s", rlm_krb5_error(inst, NULL, ret));
129 
130  return -1;
131  }
132 
133  /*
134  * Split service principal into service and host components
135  * they're needed to build the server principal in MIT,
136  * and to set the validation service in Heimdal.
137  */
138  if (inst->service_princ) {
139  size_t len;
140  /* Service principal appears to contain a host component */
141  inst->hostname = strchr(inst->service_princ, '/');
142  if (inst->hostname) {
143  len = (inst->hostname - inst->service_princ);
144  inst->hostname++;
145  } else {
146  len = strlen(inst->service_princ);
147  }
148 
149  if (len) {
150  inst->service = talloc_array(inst, char, (len + 1));
151  strlcpy(inst->service, inst->service_princ, len + 1);
152  }
153  }
154 
155 #ifdef HEIMDAL_KRB5
156  if (inst->hostname) DEBUG("Ignoring hostname component of service principal \"%s\", not "
157  "needed/supported by Heimdal", inst->hostname);
158 #else
159 
160  /*
161  * Convert the service principal string to a krb5 principal.
162  */
163  ret = krb5_sname_to_principal(inst->context, inst->hostname, inst->service, KRB5_NT_SRV_HST, &(inst->server));
164  if (ret) {
165  ERROR("Failed parsing service principal: %s", rlm_krb5_error(inst, inst->context, ret));
166 
167  return -1;
168  }
169 
170  ret = krb5_unparse_name(inst->context, inst->server, &princ_name);
171  if (ret) {
172  /* Uh? */
173  ERROR("Failed constructing service principal string: %s", rlm_krb5_error(inst, inst->context, ret));
174 
175  return -1;
176  }
177 
178  /*
179  * Not necessarily the same as the config item
180  */
181  DEBUG("Using service principal \"%s\"", princ_name);
182  krb5_free_unparsed_name(inst->context, princ_name);
183 
184  /*
185  * Setup options for getting credentials and verifying them
186  */
187  ret = krb5_get_init_creds_opt_alloc(inst->context, &(inst->gic_options)); /* For some reason the 'init' version
188  of this function is deprecated */
189  if (ret) {
190  ERROR("Couldn't allocate initial credential options: %s", rlm_krb5_error(inst, inst->context, ret));
191 
192  return -1;
193  }
194 
195  /*
196  * Perform basic checks on the keytab
197  */
198  ret = inst->keytabname ?
199  krb5_kt_resolve(inst->context, inst->keytabname, &keytab) :
200  krb5_kt_default(inst->context, &keytab);
201  if (ret) {
202  ERROR("Resolving keytab failed: %s", rlm_krb5_error(inst, inst->context, ret));
203 
204  return -1;
205  }
206 
207  ret = krb5_kt_get_name(inst->context, keytab, keytab_name, sizeof(keytab_name));
208  krb5_kt_close(inst->context, keytab);
209  if (ret) {
210  ERROR("Can't retrieve keytab name: %s", rlm_krb5_error(inst, inst->context, ret));
211 
212  return -1;
213  }
214 
215  DEBUG("Using keytab \"%s\"", keytab_name);
216 
217  MEM(inst->vic_options = talloc_zero(inst, krb5_verify_init_creds_opt));
218  krb5_verify_init_creds_opt_init(inst->vic_options);
219 #endif
220 
221 #ifdef KRB5_IS_THREAD_SAFE
222  /*
223  * Initialize the socket pool.
224  */
225  inst->pool = module_rlm_connection_pool_init(mctx->mi->conf, inst, krb5_mod_conn_create, NULL, NULL, NULL, NULL);
226  if (!inst->pool) return -1;
227 #else
229  if (!inst->conn) return -1;
230 #endif
231  return 0;
232 }
233 
234 /** Common function for transforming a User-Name string into a principal.
235  *
236  * @param[out] client Where to write the client principal.
237  * @param[in] inst of rlm_krb5.
238  * @param[in] request Current request.
239  * @param[in] context Kerberos context.
240  */
241 static rlm_rcode_t krb5_parse_user(krb5_principal *client, KRB5_UNUSED rlm_krb5_t const *inst, request_t *request,
242  krb5_context context)
243 {
244  krb5_error_code ret;
245  char *princ_name;
247 
248  username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
249 
250  /*
251  * We can only authenticate user requests which HAVE
252  * a User-Name attribute.
253  */
254  if (!username) {
255  REDEBUG("Attribute \"User-Name\" is required for authentication");
256  return RLM_MODULE_FAIL;
257  }
258 
259  ret = krb5_parse_name(context, username->vp_strvalue, client);
260  if (ret) {
261  REDEBUG("Failed parsing username as principal: %s", rlm_krb5_error(inst, context, ret));
262 
263  return RLM_MODULE_FAIL;
264  }
265 
266  krb5_unparse_name(context, *client, &princ_name);
267  RDEBUG2("Using client principal \"%s\"", princ_name);
268 #ifdef HEIMDAL_KRB5
269  free(princ_name);
270 #else
271  krb5_free_unparsed_name(context, princ_name);
272 #endif
273  return RLM_MODULE_OK;
274 }
275 
276 /** Log error message and return appropriate rcode
277  *
278  * Translate kerberos error codes into return codes.
279  * @param inst of rlm_krb5.
280  * @param request Current request.
281  * @param ret code from kerberos.
282  * @param conn used in the last operation.
283  */
285 {
286  fr_assert(ret != 0);
287 
288  if (!fr_cond_assert(inst)) return RLM_MODULE_FAIL;
289  if (!fr_cond_assert(conn)) return RLM_MODULE_FAIL; /* Silences warnings */
290 
291  switch (ret) {
292  case KRB5_LIBOS_BADPWDMATCH:
293  case KRB5KRB_AP_ERR_BAD_INTEGRITY:
294  REDEBUG("Provided password was incorrect (%i): %s", ret, rlm_krb5_error(inst, conn->context, ret));
295  return RLM_MODULE_REJECT;
296 
297  case KRB5KDC_ERR_KEY_EXP:
298  case KRB5KDC_ERR_CLIENT_REVOKED:
299  case KRB5KDC_ERR_SERVICE_REVOKED:
300  REDEBUG("Account has been locked out (%i): %s", ret, rlm_krb5_error(inst, conn->context, ret));
301  return RLM_MODULE_DISALLOW;
302 
303  case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
304  RDEBUG2("User not found (%i): %s", ret, rlm_krb5_error(inst, conn->context, ret));
305  return RLM_MODULE_NOTFOUND;
306 
307  default:
308  REDEBUG("Error verifying credentials (%i): %s", ret, rlm_krb5_error(inst, conn->context, ret));
309  return RLM_MODULE_FAIL;
310  }
311 }
312 
313 #ifdef HEIMDAL_KRB5
314 
315 /*
316  * Validate user/pass (Heimdal)
317  */
318 static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
319 {
321  rlm_rcode_t rcode;
322  krb5_error_code ret;
323  rlm_krb5_handle_t *conn;
324  krb5_principal client = NULL;
325  fr_pair_t *password;
326 
327  password = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_password);
328 
329  if (!password) {
330  REDEBUG("Attribute \"User-Password\" is required for authentication");
332  }
333 
334  /*
335  * Make sure the supplied password isn't empty
336  */
337  if (password->vp_length == 0) {
338  REDEBUG("User-Password must not be empty");
340  }
341 
342  /*
343  * Log the password
344  */
345  if (RDEBUG_ENABLED3) {
346  RDEBUG("Login attempt with password \"%pV\"", &password->data);
347  } else {
348  RDEBUG2("Login attempt with password");
349  }
350 
351 # ifdef KRB5_IS_THREAD_SAFE
352  conn = fr_pool_connection_get(inst->pool, request);
353  if (!conn) RETURN_MODULE_FAIL;
354 # else
355  conn = inst->conn;
356 # endif
357 
358  rcode = krb5_parse_user(&client, inst, request, conn->context);
359  if (rcode != RLM_MODULE_OK) goto cleanup;
360 
361  /*
362  * Verify the user, using the options we set in instantiate
363  */
364  ret = krb5_verify_user_opt(conn->context, client, password->vp_strvalue, &conn->options);
365  if (ret) {
366  rcode = krb5_process_error(inst, request, conn, ret);
367  goto cleanup;
368  }
369 
370  /*
371  * krb5_verify_user_opt adds the credentials to the ccache
372  * we specified with krb5_verify_opt_set_ccache.
373  *
374  * To make sure we don't accumulate thousands of sets of
375  * credentials, remove them again here.
376  *
377  * @todo This should definitely be optional, which means writing code for the MIT
378  * variant as well.
379  */
380  {
381  krb5_cc_cursor cursor;
382  krb5_creds cred;
383 
384  krb5_cc_start_seq_get(conn->context, conn->ccache, &cursor);
385  for (ret = krb5_cc_next_cred(conn->context, conn->ccache, &cursor, &cred);
386  ret == 0;
387  ret = krb5_cc_next_cred(conn->context, conn->ccache, &cursor, &cred)) {
388  krb5_cc_remove_cred(conn->context, conn->ccache, 0, &cred);
389  }
390  krb5_cc_end_seq_get(conn->context, conn->ccache, &cursor);
391  }
392 
393 cleanup:
394  if (client) {
395  krb5_free_principal(conn->context, client);
396  }
397 
398 # ifdef KRB5_IS_THREAD_SAFE
399  fr_pool_connection_release(inst->pool, request, conn);
400 # endif
401  RETURN_MODULE_RCODE(rcode);
402 }
403 
404 #else /* HEIMDAL_KRB5 */
405 
406 /*
407  * Validate userid/passwd (MIT)
408  */
409 static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
410 {
412  rlm_rcode_t rcode;
413  krb5_error_code ret;
414 
415  rlm_krb5_handle_t *conn;
416 
417  krb5_principal client = NULL; /* actually a pointer value */
418  krb5_creds init_creds;
419  fr_pair_t *password;
420 
421  password = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_password);
422 
423  if (!password) {
424  REDEBUG("Attribute \"User-Password\" is required for authentication");
426  }
427 
428  /*
429  * Make sure the supplied password isn't empty
430  */
431  if (password->vp_length == 0) {
432  REDEBUG("User-Password must not be empty");
434  }
435 
436  /*
437  * Log the password
438  */
439  if (RDEBUG_ENABLED3) {
440  RDEBUG("Login attempt with password \"%pV\"", &password->data);
441  } else {
442  RDEBUG2("Login attempt with password");
443  }
444 
445 # ifdef KRB5_IS_THREAD_SAFE
446  conn = fr_pool_connection_get(inst->pool, request);
447  if (!conn) RETURN_MODULE_FAIL;
448 # else
449  conn = inst->conn;
450 # endif
451 
452  /*
453  * Zero out local storage
454  */
455  memset(&init_creds, 0, sizeof(init_creds));
456 
457  /*
458  * Check we have all the required VPs, and convert the username
459  * into a principal.
460  */
461  rcode = krb5_parse_user(&client, inst, request, conn->context);
462  if (rcode != RLM_MODULE_OK) goto cleanup;
463 
464  /*
465  * Retrieve the TGT from the TGS/KDC and check we can decrypt it.
466  */
467  RDEBUG2("Retrieving and decrypting TGT");
468  ret = krb5_get_init_creds_password(conn->context, &init_creds, client, UNCONST(char *, password->vp_strvalue),
469  NULL, NULL, 0, NULL, inst->gic_options);
470  if (ret) {
471  rcode = krb5_process_error(inst, request, conn, ret);
472  goto cleanup;
473  }
474 
475  RDEBUG2("Attempting to authenticate against service principal");
476  ret = krb5_verify_init_creds(conn->context, &init_creds, inst->server, conn->keytab, NULL, inst->vic_options);
477  if (ret) rcode = krb5_process_error(inst, request, conn, ret);
478 
479 cleanup:
480  if (client) krb5_free_principal(conn->context, client);
481  krb5_free_cred_contents(conn->context, &init_creds);
482 
483 # ifdef KRB5_IS_THREAD_SAFE
484  fr_pool_connection_release(inst->pool, request, conn);
485 # endif
486  RETURN_MODULE_RCODE(rcode);
487 }
488 
489 #endif /* MIT_KRB5 */
490 
491 extern module_rlm_t rlm_krb5;
493  .common = {
494  .magic = MODULE_MAGIC_INIT,
495  .name = "krb5",
496  /*
497  * FIXME - Probably want a global mutex created on mod_load
498  */
499 #ifndef KRB5_IS_THREAD_SAFE
500  .flags = MODULE_TYPE_THREAD_UNSAFE,
501 #endif
502  .inst_size = sizeof(rlm_krb5_t),
505  .detach = mod_detach
506  },
507  .method_group = {
508  .bindings = (module_method_binding_t[]){
509  { .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
511  }
512  }
513 };
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
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:481
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:627
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:268
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:564
#define CF_IDENT_ANY
Definition: cf_util.h:78
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:139
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
#define DEBUG(fmt,...)
Definition: dhcpclient.c:39
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:267
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:280
Specifies an attribute which must be present for the module to function.
Definition: dict.h:266
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:279
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:63
free(array)
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
Context management functions for rlm_krb5.
krb5_keytab keytab
Definition: krb5.h:38
#define rlm_krb5_error(_x, _y, _z)
Definition: krb5.h:89
#define KRB5_UNUSED
Definition: krb5.h:90
krb5_context context
Definition: krb5.h:37
Instance configuration for rlm_krb5.
Definition: krb5.h:50
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
Definition: log.h:335
talloc_free(reap)
fr_log_t default_log
Definition: log.c:291
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
Definition: log.c:583
@ L_WARN
Warning.
Definition: log.h:57
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
module_instance_t const * mi
Instance of the module being instantiated.
Definition: module_ctx.h:42
module_instance_t * mi
Module instance to detach.
Definition: module_ctx.h:57
module_instance_t * mi
Instance of the module being instantiated.
Definition: module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition: module_ctx.h:41
Temporary structure to hold arguments for detach calls.
Definition: module_ctx.h:56
Temporary structure to hold arguments for instantiation calls.
Definition: module_ctx.h:50
fr_pool_t * module_rlm_connection_pool_init(CONF_SECTION *module, void *opaque, fr_pool_connection_create_t c, fr_pool_connection_alive_t a, char const *log_prefix, char const *trigger_prefix, fr_pair_list_t *trigger_args)
Initialise a module specific connection pool.
Definition: module_rlm.c:308
module_t common
Common fields presented by all modules.
Definition: module_rlm.h:39
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition: pair.c:693
void fr_pool_connection_release(fr_pool_t *pool, request_t *request, void *conn)
Release a connection.
Definition: pool.c:1407
void fr_pool_free(fr_pool_t *pool)
Delete a connection pool.
Definition: pool.c:1329
void * fr_pool_connection_get(fr_pool_t *pool, request_t *request)
Reserve a connection in the connection pool.
Definition: pool.c:1392
static const conf_parser_t config[]
Definition: base.c:183
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define RDEBUG2(fmt,...)
Definition: radclient.h:54
#define RDEBUG(fmt,...)
Definition: radclient.h:53
#define WARN(fmt,...)
Definition: radclient.h:47
static bool cleanup
Definition: radsniff.c:60
#define RETURN_MODULE_RCODE(_rcode)
Definition: rcode.h:64
#define RETURN_MODULE_INVALID
Definition: rcode.h:59
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
@ RLM_MODULE_OK
The module is OK, continue.
Definition: rcode.h:43
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition: rcode.h:42
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
Definition: rcode.h:46
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition: rcode.h:41
@ RLM_MODULE_NOTFOUND
User not found.
Definition: rcode.h:47
static int mod_detach(module_detach_ctx_t const *mctx)
Definition: rlm_krb5.c:60
static fr_dict_attr_t const * attr_user_password
Definition: rlm_krb5.c:51
fr_dict_autoload_t rlm_krb5_dict[]
Definition: rlm_krb5.c:45
static rlm_rcode_t krb5_process_error(rlm_krb5_t const *inst, request_t *request, rlm_krb5_handle_t *conn, int ret)
Log error message and return appropriate rcode.
Definition: rlm_krb5.c:284
fr_dict_attr_autoload_t rlm_krb5_dict_attr[]
Definition: rlm_krb5.c:54
static fr_dict_t const * dict_radius
Definition: rlm_krb5.c:42
static unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_krb5.c:409
module_rlm_t rlm_krb5
Definition: rlm_krb5.c:492
static rlm_rcode_t krb5_parse_user(krb5_principal *client, KRB5_UNUSED rlm_krb5_t const *inst, request_t *request, krb5_context context)
Common function for transforming a User-Name string into a principal.
Definition: rlm_krb5.c:241
static fr_dict_attr_t const * attr_user_name
Definition: rlm_krb5.c:50
static const conf_parser_t module_config[]
Definition: rlm_krb5.c:36
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_krb5.c:82
static int instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_rest.c:1302
username
Definition: rlm_securid.c:420
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition: section.h:40
@ MODULE_TYPE_THREAD_UNSAFE
Module is not threadsafe.
Definition: module.h:48
CONF_SECTION * conf
Module's instance configuration.
Definition: module.h:329
void * data
Module's instance data.
Definition: module.h:271
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition: module.h:151
Named methods exported by a module.
Definition: module.h:173
RETURN_MODULE_FAIL
fr_assert(0)
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
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
#define talloc_get_type_abort_const
Definition: talloc.h:282
#define fr_time_delta_wrap(_time)
Definition: time.h:152
int nonnull(2, 5))