The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_digest.c
Go to the documentation of this file.
1/*
2 * This program is 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 (at
5 * 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: d1c817a3f48b95c6f4251390e00ea49f2c759aed $
19 * @file rlm_digest.c
20 * @brief Handles SIP digest authentication requests from Cisco SIP servers.
21 *
22 * @copyright 2002,2006 The FreeRADIUS server project
23 * @copyright 2002 Alan DeKok (aland@freeradius.org)
24 */
25RCSID("$Id: d1c817a3f48b95c6f4251390e00ea49f2c759aed $")
26
27#include <freeradius-devel/server/base.h>
28#include <freeradius-devel/server/module_rlm.h>
29
30#include <freeradius-devel/util/base16.h>
31#include <freeradius-devel/util/md5.h>
32
33typedef struct {
36
38static fr_dict_t const *dict_radius;
39
42 { .out = &dict_freeradius, .proto = "freeradius" },
43 { .out = &dict_radius, .proto = "radius" },
45};
46
49
63
66 { .out = &attr_auth_type, .name = "Auth-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
67 { .out = &attr_cleartext_password, .name = "Password.Cleartext", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
68
69 { .out = &attr_digest_response, .name = "Digest-Response", .type = FR_TYPE_STRING, .dict = &dict_radius },
70 { .out = &attr_digest_attributes, .name = "Digest-Attributes", .type = FR_TYPE_TLV, .dict = &dict_radius },
71 { .out = &attr_digest_algorithm, .name = "Digest-Attributes.Algorithm", .type = FR_TYPE_STRING, .dict = &dict_radius },
72 { .out = &attr_digest_body_digest, .name = "Digest-Attributes.Body-Digest", .type = FR_TYPE_STRING, .dict = &dict_radius },
73 { .out = &attr_digest_cnonce, .name = "Digest-Attributes.Cnonce", .type = FR_TYPE_STRING, .dict = &dict_radius },
74 { .out = &attr_digest_ha1, .name = "Digest-Attributes.HA1", .type = FR_TYPE_STRING, .dict = &dict_radius },
75 { .out = &attr_digest_method, .name = "Digest-Attributes.Method", .type = FR_TYPE_STRING, .dict = &dict_radius },
76 { .out = &attr_digest_nonce, .name = "Digest-Attributes.Nonce", .type = FR_TYPE_STRING, .dict = &dict_radius },
77 { .out = &attr_digest_nonce_count, .name = "Digest-Attributes.Nonce-Count", .type = FR_TYPE_STRING, .dict = &dict_radius },
78 { .out = &attr_digest_qop, .name = "Digest-Attributes.Qop", .type = FR_TYPE_STRING, .dict = &dict_radius },
79 { .out = &attr_digest_realm, .name = "Digest-Attributes.Realm", .type = FR_TYPE_STRING, .dict = &dict_radius },
80 { .out = &attr_digest_uri, .name = "Digest-Attributes.Uri", .type = FR_TYPE_STRING, .dict = &dict_radius },
81 { .out = &attr_digest_user_name, .name = "Digest-Attributes.User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
82
84};
85
86static unlang_action_t CC_HINT(nonnull) mod_authorize(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
87{
88 rlm_digest_t const *inst = talloc_get_type_abort(mctx->mi->data, rlm_digest_t);
90
91 /*
92 * Find the first attribute which is parented by Digest-Attributes.
93 */
94 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_digest_attributes);
96
97 if (!inst->auth_type) {
98 WARN("No 'authenticate %s {...}' section or 'Auth-Type = %s' set. Cannot setup Digest authentication",
99 mctx->mi->name, mctx->mi->name);
101 }
102
103 /*
104 * Everything's OK, add a digest authentication type.
105 */
107
109}
110
112{
113 fr_pair_t *vp;
114
115 vp = fr_pair_find_by_da(list, NULL, da);
116 if (!vp) {
117 REDEBUG("No Digest-Attributes.%s: Cannot perform Digest authentication", da->name);
118 return NULL;
119 }
120
121 if (vp->vp_length >= FR_MAX_STRING_LEN) {
122 REDEBUG("Invalid Digest-Attributes.%s: Cannot perform Digest authentication", da->name);
123 return NULL;
124 }
125
126 return vp;
127}
128
129/*
130 * Perform all of the wondrous variants of digest authentication.
131 */
132static unlang_action_t CC_HINT(nonnull) mod_authenticate(unlang_result_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
133{
134 size_t a1_len, a2_len, kd_len;
135 uint8_t a1[(FR_MAX_STRING_LEN + 1) * 5]; /* can be 5 attributes */
136 uint8_t a2[(FR_MAX_STRING_LEN + 1) * 3]; /* can be 3 attributes */
137 uint8_t kd[(FR_MAX_STRING_LEN + 1) * 5];
138 uint8_t hash[16]; /* MD5 output */
139 uint8_t digest[16];
140 fr_pair_t *vp, *passwd, *algo;
141 fr_pair_t *qop, *nonce;
142 fr_pair_list_t *list;
143
144 /*
145 * We require access to the plain-text password, or to the
146 * Digest-Attributes.HA1 parameter.
147 */
148 passwd = fr_pair_find_by_da_nested(&request->control_pairs, NULL, attr_digest_ha1);
149 if (passwd) {
150 if (passwd->vp_length != 32) {
151 REDEBUG("Digest-Attributes.HA1 has invalid length, authentication failed");
153 }
154 } else {
155 passwd = fr_pair_find_by_da_nested(&request->control_pairs, NULL, attr_cleartext_password);
156 }
157 if (!passwd) {
158 REDEBUG("Password.Cleartext or Digest-Attributes.HA1 is required for authentication");
160 }
161
162 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_digest_attributes);
163 if (!vp) {
164 REDEBUG("Digest-Attributes is required for authentication");
166 }
167 list = &vp->vp_group;
168
169 /*
170 * We require access to the Digest-Attributes.Nonce
171 */
172 nonce = digest_find_vp(request, list, attr_digest_nonce);
173 if (!nonce) RETURN_UNLANG_INVALID;
174
175 /*
176 * A1 = Digest-Attributes.User-Name ":" Realm ":" Password
177 */
178 vp = digest_find_vp(request, list, attr_digest_user_name);
180 memcpy(&a1[0], vp->vp_octets, vp->vp_length);
181 a1_len = vp->vp_length;
182
183 a1[a1_len] = ':';
184 a1_len++;
185
186 vp = digest_find_vp(request, list, attr_digest_realm);
188 memcpy(&a1[a1_len], vp->vp_octets, vp->vp_length);
189 a1_len += vp->vp_length;
190
191 a1[a1_len] = ':';
192 a1_len++;
193
194 if (passwd->da == attr_cleartext_password) {
195 if (passwd->vp_length >= FR_MAX_STRING_LEN) RETURN_UNLANG_INVALID;
196 memcpy(&a1[a1_len], passwd->vp_octets, passwd->vp_length);
197 a1_len += passwd->vp_length;
198 a1[a1_len] = '\0';
199 RDEBUG2("A1 = %s", a1);
200 } else {
201 a1[a1_len] = '\0';
202 RDEBUG2("A1 = %s (using Digest-Attributes.HA1)", a1);
203 a1_len = 16;
204 }
205
206 /*
207 * See which variant we calculate.
208 * Assume MD5 if no Digest-Algorithm attribute received
209 */
211 if ((!algo) ||
212 (strcasecmp(algo->vp_strvalue, "MD5") == 0)) {
213 /*
214 * Set A1 to Digest-Attributes.HA1 if no User-Password found
215 */
216 if (passwd->da == attr_digest_ha1) {
217 if (fr_base16_decode(NULL, &FR_DBUFF_TMP(&a1[0], sizeof(a1)),
218 &FR_SBUFF_IN(passwd->vp_strvalue, passwd->vp_length), false) != 16) {
219 RDEBUG2("Invalid text in Digest-Attributes.HA1");
221 }
222 }
223
224 } else if (strcasecmp(algo->vp_strvalue, "MD5-sess") == 0) {
225 /*
226 * K1 = H(A1) : Digest-Attributes.Nonce ... : H(A2)
227 *
228 * If we find Digest-Attributes.HA1, we assume it contains
229 * H(A1).
230 */
231 if (passwd->da == attr_cleartext_password) {
232 fr_md5_calc(hash, &a1[0], a1_len);
233 fr_base16_encode(&FR_SBUFF_OUT((char *) &a1[0], 32 + 1), &FR_DBUFF_TMP(hash, 16));
234 } else { /* MUST be Digest-Attributes.HA1 */
235 memcpy(&a1[0], passwd->vp_strvalue, 32);
236 }
237 a1_len = 32;
238
239 a1[a1_len] = ':';
240 a1_len++;
241
242 /*
243 * Tack on the Digest-Attributes.Nonce. Length must be even
244 */
245 if ((nonce->vp_length & 1) != 0) {
246 REDEBUG("Received Digest-Attributes.Nonce hex string with invalid length: Cannot perform Digest authentication");
248 }
249 memcpy(&a1[a1_len], nonce->vp_octets, nonce->vp_length);
250 a1_len += nonce->vp_length;
251
252 a1[a1_len] = ':';
253 a1_len++;
254
255 vp = digest_find_vp(request, list, attr_digest_cnonce);
257
258 /*
259 * Digest-Attributes.CNonce length must be even
260 */
261 if ((vp->vp_length & 1) != 0) {
262 REDEBUG("Received Digest-Attributes.CNonce hex string with invalid length: Cannot perform Digest authentication");
264 }
265 memcpy(&a1[a1_len], vp->vp_octets, vp->vp_length);
266 a1_len += vp->vp_length;
267
268 } else {
269 /*
270 * We check for "MD5-sess" and "MD5".
271 * Anything else is an error.
272 */
273 REDEBUG("Unknown Digest-Attributes.Algorithm %s: Cannot perform Digest authentication", algo->vp_strvalue);
275 }
276
277 /*
278 * A2 = Digest-Attributes.Method ":" Digest-Attributes.URI
279 */
280 vp = digest_find_vp(request, list, attr_digest_method);
282 memcpy(&a2[0], vp->vp_octets, vp->vp_length);
283 a2_len = vp->vp_length;
284
285 a2[a2_len] = ':';
286 a2_len++;
287
288 vp = digest_find_vp(request, list, attr_digest_uri);
290 memcpy(&a2[a2_len], vp->vp_octets, vp->vp_length);
291 a2_len += vp->vp_length;
292
293 /*
294 * QOP is "auth-int", tack on ": Digest-Attributes.Body-Digest"
295 */
297 if (qop) {
298 if (strcasecmp(qop->vp_strvalue, "auth-int") == 0) {
299 fr_pair_t *body;
300
301 /*
302 * Add in Digest-Attributes.Body-Digest
303 */
304 a2[a2_len] = ':';
305 a2_len++;
306
307 /*
308 * Must be a hex representation of an MD5 digest.
309 */
310 body = digest_find_vp(request, list, attr_digest_body_digest);
311 if (!body) RETURN_UNLANG_INVALID;
312
313 if ((a2_len + body->vp_length) > sizeof(a2)) {
314 REDEBUG("Digest-Attributes.Body-Digest is too long");
316 }
317
318 memcpy(a2 + a2_len, body->vp_octets, body->vp_length);
319 a2_len += body->vp_length;
320
321 } else if (strcasecmp(qop->vp_strvalue, "auth") != 0) {
322 REDEBUG("%pP - Unknown value: Cannot perform Digest authentication", qop);
324 }
325 }
326
327 a2[a2_len] = '\0';
328 RDEBUG2("A2 = %s", a2);
329
330 /*
331 * KD = H(A1) : Digest-Attributes.Nonce ... : H(A2).
332 * Compute MD5 if Digest-Attributes.Algorithm == "MD5-Sess",
333 * or if we found a User-Password.
334 */
335 if (((algo != NULL) && (strcasecmp(algo->vp_strvalue, "MD5-Sess") == 0)) ||
336 (passwd->da == attr_cleartext_password)) {
337 a1[a1_len] = '\0';
338 fr_md5_calc(&hash[0], &a1[0], a1_len);
339 } else {
340 memcpy(&hash[0], &a1[0], a1_len);
341 }
342 fr_base16_encode(&FR_SBUFF_OUT((char *) kd, (sizeof(hash) * 2) + 1), &FR_DBUFF_TMP(hash, sizeof(hash)));
343
344 RHEXDUMP_INLINE3(hash, sizeof(hash), "H(A1)");
345
346 kd_len = 32;
347
348 kd[kd_len] = ':';
349 kd_len++;
350
351 memcpy(&kd[kd_len], nonce->vp_octets, nonce->vp_length);
352 kd_len += nonce->vp_length;
353
354 /*
355 * No QOP defined. Do RFC 2069 compatibility.
356 */
357 if (!qop) {
358 /*
359 * Do nothing here.
360 */
361
362 } else { /* Digest-Attributes.QOP MUST be "auth" or "auth-int" */
363 /*
364 * Tack on ":" Digest-Attributes.Nonce-Count ":" Digest-Attributes.CNonce
365 * ":" Digest-Attributes.QOP
366 */
367 kd[kd_len] = ':';
368 kd_len++;
369
370 vp = digest_find_vp(request, list, attr_digest_nonce_count);
372 memcpy(&kd[kd_len], vp->vp_octets, vp->vp_length);
373 kd_len += vp->vp_length;
374
375 kd[kd_len] = ':';
376 kd_len++;
377
378 vp = digest_find_vp(request, list, attr_digest_cnonce);
380 memcpy(&kd[kd_len], vp->vp_octets, vp->vp_length);
381 kd_len += vp->vp_length;
382
383 kd[kd_len] = ':';
384 kd_len++;
385
386 memcpy(&kd[kd_len], qop->vp_octets, qop->vp_length);
387 kd_len += qop->vp_length;
388 }
389
390 /*
391 * Tack on ":" H(A2)
392 */
393 kd[kd_len] = ':';
394 kd_len++;
395
396 fr_md5_calc(&hash[0], &a2[0], a2_len);
397
398 fr_base16_encode(&FR_SBUFF_OUT((char *) kd + kd_len, (sizeof(hash) * 2) + 1), &FR_DBUFF_TMP(hash, sizeof(hash)));
399
400 RHEXDUMP_INLINE3(hash, sizeof(hash), "H(A2)");
401
402 kd_len += 32;
403
404 kd[kd_len] = 0;
405
406 RDEBUG2("KD = %s\n", &kd[0]);
407
408 /*
409 * Take the hash of KD.
410 */
411 fr_md5_calc(&hash[0], &kd[0], kd_len);
412 memcpy(&kd[0], &hash[0], 16);
413
414 /*
415 * Get the binary value of Digest-Response. This isn't
416 * inside of the Digest-Attributes group.
417 */
418 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_digest_response);
419 if (!vp) {
420 REDEBUG("No Digest-Response attribute in the request. Cannot perform digest authentication");
422 }
423
424 if (vp->vp_length != 32) {
425 REDEBUG("Digest-Response has incorrect length (%zu), expected 32 hex characters",
426 vp->vp_length);
428 }
429
430 if (fr_base16_decode(NULL, &FR_DBUFF_TMP(&digest[0], sizeof(digest)),
431 &FR_SBUFF_IN(vp->vp_strvalue, vp->vp_length), false) != (ssize_t)(vp->vp_length >> 1)) {
432 RDEBUG2("Invalid text in Digest-Response");
434 }
435
436 RDEBUG3("Comparing hashes, received: %pV, calculated: %pH", &vp->data, fr_box_octets(kd, 16));
437
438 /*
439 * And finally, compare the digest in the packet with KD.
440 */
441 if (fr_digest_cmp(&kd[0], &digest[0], 16) == 0) RETURN_UNLANG_OK;
442
443 REDEBUG("FAILED authentication");
445}
446
447
448/*
449 * Create instance for our module. Allocate space for
450 * instance structure and read configuration parameters
451 */
452static int mod_instantiate(module_inst_ctx_t const *mctx)
453{
454 rlm_digest_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_digest_t);
455
456 inst->auth_type = fr_dict_enum_by_name(attr_auth_type, mctx->mi->name, -1);
457 if (!inst->auth_type) {
458 WARN("Failed to find 'authenticate %s {...}' section. Digest authentication will likely not work",
459 mctx->mi->name);
460 }
461
462 return 0;
463}
464
465/*
466 * The module name should be the only globally exported symbol.
467 * That is, everything else should be 'static'.
468 *
469 * If the module needs to temporarily modify it's instantiation
470 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
471 * The server will then take care of ensuring that the module
472 * is single-threaded.
473 */
476 .common = {
477 .magic = MODULE_MAGIC_INIT,
478 .name = "digest",
479 .inst_size = sizeof(rlm_digest_t),
480 .instantiate = mod_instantiate,
481 },
482 .method_group = {
483 .bindings = (module_method_binding_t[]){
484 { .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
485 { .section = SECTION_NAME("recv", "Access-Request"), .method = mod_authorize },
487 }
488 }
489};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
#define fr_base16_encode(_out, _in)
Definition base16.h:57
#define fr_base16_decode(_err, _out, _in, _no_trailing)
Definition base16.h:95
#define RCSID(id)
Definition build.h:487
#define UNUSED
Definition build.h:317
#define CF_IDENT_ANY
Definition cf_util.h:78
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:524
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:294
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:307
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:313
fr_dict_enum_value_t const * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Definition dict_util.c:3708
Specifies an attribute which must be present for the module to function.
Definition dict.h:293
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:306
Value of an enumerated attribute.
Definition dict.h:255
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
#define RDEBUG3(fmt,...)
Definition log.h:355
#define RHEXDUMP_INLINE3(_data, _len, _fmt,...)
Definition log.h:698
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
long int ssize_t
void fr_md5_calc(uint8_t out[static MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen)
Perform a single digest operation on a single input buffer.
unsigned char uint8_t
int fr_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length)
Do a comparison of two authentication digests by comparing the FULL data.
Definition misc.c:505
int strcasecmp(char *s1, char *s2)
Definition missing.c:66
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
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 instantiation calls.
Definition module_ctx.h:50
bool module_rlm_section_type_set(request_t *request, fr_dict_attr_t const *type_da, fr_dict_enum_value_t const *enumv)
Set the next section type if it's not already set.
Definition module_rlm.c:418
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
fr_pair_t * fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find a pair with a matching fr_dict_attr_t, by walking the nested fr_dict_attr_t tree.
Definition pair.c:781
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:704
#define REDEBUG(fmt,...)
#define RDEBUG2(fmt,...)
#define WARN(fmt,...)
#define RETURN_UNLANG_INVALID
Definition rcode.h:66
#define RETURN_UNLANG_REJECT
Definition rcode.h:62
#define RETURN_UNLANG_OK
Definition rcode.h:64
#define RETURN_UNLANG_NOOP
Definition rcode.h:69
static const fr_dict_attr_t * attr_digest_user_name
Definition rlm_digest.c:62
static fr_pair_t * digest_find_vp(request_t *request, fr_pair_list_t *list, fr_dict_attr_t const *da)
Definition rlm_digest.c:111
static const fr_dict_attr_t * attr_digest_body_digest
Definition rlm_digest.c:53
static const fr_dict_attr_t * attr_digest_ha1
Definition rlm_digest.c:55
static const fr_dict_attr_t * attr_digest_method
Definition rlm_digest.c:56
static const fr_dict_attr_t * attr_digest_qop
Definition rlm_digest.c:59
static const fr_dict_attr_t * attr_cleartext_password
Definition rlm_digest.c:48
static const fr_dict_attr_t * attr_digest_attributes
Definition rlm_digest.c:51
static fr_dict_t const * dict_freeradius
Definition rlm_digest.c:37
module_rlm_t rlm_digest
Definition rlm_digest.c:475
static const fr_dict_attr_t * attr_digest_cnonce
Definition rlm_digest.c:54
static fr_dict_t const * dict_radius
Definition rlm_digest.c:38
static const fr_dict_attr_t * attr_digest_algorithm
Definition rlm_digest.c:52
static unlang_action_t mod_authorize(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_digest.c:86
static const fr_dict_attr_t * attr_digest_response
Definition rlm_digest.c:50
static const fr_dict_attr_t * attr_digest_uri
Definition rlm_digest.c:61
static const fr_dict_attr_t * attr_digest_realm
Definition rlm_digest.c:60
static const fr_dict_attr_t * attr_digest_nonce_count
Definition rlm_digest.c:58
fr_dict_enum_value_t const * auth_type
Definition rlm_digest.c:34
static const fr_dict_attr_t * attr_auth_type
Definition rlm_digest.c:47
fr_dict_attr_autoload_t rlm_digest_dict_attr[]
Definition rlm_digest.c:65
static const fr_dict_attr_t * attr_digest_nonce
Definition rlm_digest.c:57
static unlang_action_t mod_authenticate(unlang_result_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
Definition rlm_digest.c:132
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition rlm_digest.c:452
fr_dict_autoload_t rlm_digest_dict[]
Definition rlm_digest.c:41
static unsigned int hash(char const *username, unsigned int tablesize)
Definition rlm_passwd.c:132
#define FR_SBUFF_IN(_start, _len_or_end)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:40
char const * name
Instance name e.g. user_database.
Definition module.h:355
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:291
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:152
Named methods exported by a module.
Definition module.h:174
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
#define FR_MAX_STRING_LEN
Definition value.h:30
int nonnull(2, 5))
#define fr_box_octets(_val, _len)
Definition value.h:311