The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rlm_opendirectory.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, version 2 of the
4  * License as published by the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public License
12  * along with this program; if not, write to the Free Software
13  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
14  */
15 
16 /**
17  * $Id: 55c4c26babbcb88883144c0f55ad9caf33c682fc $
18  * @file rlm_opendirectory.c
19  * @brief Allows authentication against OpenDirectory and enforces ACLS.
20  *
21  * authentication: Apple Open Directory authentication
22  * authorization: enforces ACLs
23  *
24  * @copyright 2007 Apple Inc.
25  */
26 
27 /*
28  * For a typical Makefile, add linker flag like this:
29  * LDFLAGS = -framework DirectoryService
30  */
32 #include <freeradius-devel/server/base.h>
33 #include <freeradius-devel/server/module_rlm.h>
34 #include <freeradius-devel/util/debug.h>
35 #include <freeradius-devel/util/perm.h>
36 
37 #include <ctype.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <grp.h>
41 #include <pwd.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 
45 #include <DirectoryService/DirectoryService.h>
46 #include <membership.h>
47 
48 typedef struct {
51 
52 #ifndef HAVE_DECL_MBR_CHECK_SERVICE_MEMBERSHIP
53 int mbr_check_service_membership(uuid_t const user, char const *servicename, int *ismember);
54 #endif
55 #ifndef HAVE_DECL_MBR_CHECK_MEMBERSHIP_REFRESH
56 int mbr_check_membership_refresh(uuid_t const user, uuid_t group, int *ismember);
57 #endif
58 
59 /* RADIUS service ACL constants */
60 #define kRadiusSACLName "com.apple.access_radius"
61 #define kRadiusServiceName "radius"
62 
63 static fr_dict_t const *dict_freeradius;
64 static fr_dict_t const *dict_radius;
65 
68  { .out = &dict_freeradius, .proto = "freeradius" },
69  { .out = &dict_radius, .proto = "radius" },
70  { NULL }
71 };
72 
76 
79  { .out = &attr_auth_type, .name = "Auth-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
80  { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
81  { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
82  { NULL }
83 };
84 
85 /*
86  * od_check_passwd
87  *
88  * Returns: ds err
89  */
90 
91 static long od_check_passwd(request_t *request, char const *uname, char const *password)
92 {
93  long result = eDSAuthFailed;
94  tDirReference dsRef = 0;
95  tDataBuffer *tDataBuff;
96  tDirNodeReference nodeRef = 0;
97  long status = eDSNoErr;
98  tContextData context = 0;
99  uint32_t nodeCount = 0;
100  uint32_t attrIndex = 0;
101  tDataList *nodeName = NULL;
102  tAttributeEntryPtr pAttrEntry = NULL;
103  tDataList *pRecName = NULL;
104  tDataList *pRecType = NULL;
105  tDataList *pAttrType = NULL;
106  uint32_t recCount = 0;
107  tRecordEntry *pRecEntry = NULL;
108  tAttributeListRef attrListRef = 0;
109  char *pUserLocation = NULL;
110  char *pUserName = NULL;
111  tAttributeValueListRef valueRef = 0;
112  tAttributeValueEntry *pValueEntry = NULL;
113  tDataList *pUserNode = NULL;
114  tDirNodeReference userNodeRef = 0;
115  tDataBuffer *pStepBuff = NULL;
116  tDataNode *pAuthType = NULL;
117  tAttributeValueEntry *pRecordType = NULL;
118  uint32_t uiCurr = 0;
119  uint32_t uiLen = 0;
120  uint32_t pwLen = 0;
121 
122  if (!uname || !password)
123  return result;
124 
125  do
126  {
127  status = dsOpenDirService( &dsRef );
128  if ( status != eDSNoErr )
129  return result;
130 
131  tDataBuff = dsDataBufferAllocate( dsRef, 4096 );
132  if (!tDataBuff)
133  break;
134 
135  /* find user on search node */
136  status = dsFindDirNodes( dsRef, tDataBuff, NULL, eDSSearchNodeName, &nodeCount, &context );
137  if (status != eDSNoErr || nodeCount < 1)
138  break;
139 
140  status = dsGetDirNodeName( dsRef, tDataBuff, 1, &nodeName );
141  if (status != eDSNoErr)
142  break;
143 
144  status = dsOpenDirNode( dsRef, nodeName, &nodeRef );
145  dsDataListDeallocate( dsRef, nodeName );
146  free( nodeName );
147  nodeName = NULL;
148  if (status != eDSNoErr)
149  break;
150 
151  pRecName = dsBuildListFromStrings( dsRef, uname, NULL );
152  pRecType = dsBuildListFromStrings( dsRef, kDSStdRecordTypeUsers, kDSStdRecordTypeComputers, kDSStdRecordTypeMachines, NULL );
153  pAttrType = dsBuildListFromStrings( dsRef, kDSNAttrMetaNodeLocation, kDSNAttrRecordName, kDSNAttrRecordType, NULL );
154 
155  recCount = 1;
156  status = dsGetRecordList( nodeRef, tDataBuff, pRecName, eDSExact, pRecType,
157  pAttrType, 0, &recCount, &context );
158  if ( status != eDSNoErr || recCount == 0 )
159  break;
160 
161  status = dsGetRecordEntry( nodeRef, tDataBuff, 1, &attrListRef, &pRecEntry );
162  if ( status != eDSNoErr )
163  break;
164 
165  for ( attrIndex = 1; (attrIndex <= pRecEntry->fRecordAttributeCount) && (status == eDSNoErr); attrIndex++ )
166  {
167  status = dsGetAttributeEntry( nodeRef, tDataBuff, attrListRef, attrIndex, &valueRef, &pAttrEntry );
168  if ( status == eDSNoErr && pAttrEntry != NULL )
169  {
170  if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
171  {
172  status = dsGetAttributeValue( nodeRef, tDataBuff, 1, valueRef, &pValueEntry );
173  if ( status == eDSNoErr && pValueEntry != NULL )
174  {
175  pUserLocation = talloc_zero_array(request, char, pValueEntry->fAttributeValueData.fBufferLength + 1);
176  memcpy( pUserLocation, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength );
177  }
178  }
179  else
180  if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
181  {
182  status = dsGetAttributeValue( nodeRef, tDataBuff, 1, valueRef, &pValueEntry );
183  if ( status == eDSNoErr && pValueEntry != NULL )
184  {
185  pUserName = talloc_zero_array(request, char, pValueEntry->fAttributeValueData.fBufferLength + 1);
186  memcpy( pUserName, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength );
187  }
188  }
189  else
190  if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordType ) == 0 )
191  {
192  status = dsGetAttributeValue( nodeRef, tDataBuff, 1, valueRef, &pValueEntry );
193  if ( status == eDSNoErr && pValueEntry != NULL )
194  {
195  pRecordType = pValueEntry;
196  pValueEntry = NULL;
197  }
198  }
199 
200  if ( pValueEntry != NULL ) {
201  dsDeallocAttributeValueEntry( dsRef, pValueEntry );
202  pValueEntry = NULL;
203  }
204  if ( pAttrEntry != NULL ) {
205  dsDeallocAttributeEntry( dsRef, pAttrEntry );
206  pAttrEntry = NULL;
207  }
208  dsCloseAttributeValueList( valueRef );
209  valueRef = 0;
210  }
211  }
212 
213  pUserNode = dsBuildFromPath( dsRef, pUserLocation, "/" );
214  status = dsOpenDirNode( dsRef, pUserNode, &userNodeRef );
215  dsDataListDeallocate( dsRef, pUserNode );
216  free( pUserNode );
217  pUserNode = NULL;
218  if ( status != eDSNoErr )
219  break;
220 
221  pStepBuff = dsDataBufferAllocate( dsRef, 128 );
222 
223  pAuthType = dsDataNodeAllocateString( dsRef, kDSStdAuthNodeNativeClearTextOK );
224  uiCurr = 0;
225 
226  if (!pUserName) {
227  RDEBUG2("Failed to find user name");
228  break;
229  }
230 
231  /* User name */
232  uiLen = (uint32_t)strlen( pUserName );
233  memcpy( &(tDataBuff->fBufferData[ uiCurr ]), &uiLen, sizeof(uiLen) );
234  uiCurr += (uint32_t)sizeof( uiLen );
235  memcpy( &(tDataBuff->fBufferData[ uiCurr ]), pUserName, uiLen );
236  uiCurr += uiLen;
237 
238  /* pw */
239  pwLen = (uint32_t)strlen( password );
240  memcpy( &(tDataBuff->fBufferData[ uiCurr ]), &pwLen, sizeof(pwLen) );
241  uiCurr += (uint32_t)sizeof( pwLen );
242  memcpy( &(tDataBuff->fBufferData[ uiCurr ]), password, pwLen );
243  uiCurr += pwLen;
244 
245  tDataBuff->fBufferLength = uiCurr;
246 
247  result = dsDoDirNodeAuthOnRecordType( userNodeRef, pAuthType, 1, tDataBuff, pStepBuff, NULL, &pRecordType->fAttributeValueData );
248  }
249  while ( 0 );
250 
251  /* clean up */
252  if (pAuthType != NULL) {
253  dsDataNodeDeAllocate( dsRef, pAuthType );
254  pAuthType = NULL;
255  }
256  if (pRecordType != NULL) {
257  dsDeallocAttributeValueEntry( dsRef, pRecordType );
258  pRecordType = NULL;
259  }
260  if (tDataBuff != NULL) {
261  bzero( tDataBuff, tDataBuff->fBufferSize );
262  dsDataBufferDeAllocate( dsRef, tDataBuff );
263  tDataBuff = NULL;
264  }
265  if (pStepBuff != NULL) {
266  dsDataBufferDeAllocate( dsRef, pStepBuff );
267  pStepBuff = NULL;
268  }
269  if (pUserLocation != NULL) {
270  talloc_free(pUserLocation);
271  pUserLocation = NULL;
272  }
273  if (pUserName != NULL) {
274  talloc_free(pUserName);
275  pUserName = NULL;
276  }
277  if (pRecName != NULL) {
278  dsDataListDeallocate( dsRef, pRecName );
279  free( pRecName );
280  pRecName = NULL;
281  }
282  if (pRecType != NULL) {
283  dsDataListDeallocate( dsRef, pRecType );
284  free( pRecType );
285  pRecType = NULL;
286  }
287  if (pAttrType != NULL) {
288  dsDataListDeallocate( dsRef, pAttrType );
289  free( pAttrType );
290  pAttrType = NULL;
291  }
292  if (nodeRef != 0) {
293  dsCloseDirNode(nodeRef);
294  nodeRef = 0;
295  }
296  if (dsRef != 0) {
297  dsCloseDirService(dsRef);
298  dsRef = 0;
299  }
300 
301  return result;
302 }
303 
304 
305 /*
306  * Check the users password against the standard UNIX
307  * password table.
308  */
309 static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
310 {
311  int ret;
312  long odResult = eDSAuthFailed;
313  fr_pair_t *username, *password;
314 
315  username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
316  password = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_password);
317 
318  /*
319  * We can only authenticate user requests which HAVE
320  * a User-Name attribute.
321  */
322  if (!username) {
323  REDEBUG("Attribute \"User-Name\" is required for authentication");
325  }
326 
327  if (!password) {
328  REDEBUG("Attribute \"User-Password\" is required for authentication");
330  }
331 
332  /*
333  * Make sure the supplied password isn't empty
334  */
335  if (password->vp_length == 0) {
336  REDEBUG("User-Password must not be empty");
338  }
339 
340  /*
341  * Log the password
342  */
343  if (RDEBUG_ENABLED3) {
344  RDEBUG("Login attempt with password \"%pV\"", &password->data);
345  } else {
346  RDEBUG2("Login attempt with password");
347  }
348 
349  odResult = od_check_passwd(request, username->vp_strvalue,
350  password->vp_strvalue);
351  switch (odResult) {
352  case eDSNoErr:
353  ret = RLM_MODULE_OK;
354  break;
355 
356  case eDSAuthUnknownUser:
357  case eDSAuthInvalidUserName:
358  case eDSAuthNewPasswordRequired:
359  case eDSAuthPasswordExpired:
360  case eDSAuthAccountDisabled:
361  case eDSAuthAccountExpired:
362  case eDSAuthAccountInactive:
363  case eDSAuthInvalidLogonHours:
364  case eDSAuthInvalidComputer:
365  ret = RLM_MODULE_DISALLOW;
366  break;
367 
368  default:
369  ret = RLM_MODULE_REJECT;
370  break;
371  }
372 
373  if (ret != RLM_MODULE_OK) {
374  RDEBUG2("Invalid password: %pV", &username->data);
375  return ret;
376  }
377 
379 }
380 
381 
382 /*
383  * member of the radius group?
384  */
385 static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
386 {
388  struct passwd *userdata = NULL;
389  int ismember = 0;
390  fr_client_t *client = NULL;
391  uuid_t uuid;
392  uuid_t guid_sacl;
393  uuid_t guid_nasgroup;
394  int err;
395  char host_ipaddr[128] = {0};
396  gid_t gid;
398 
399  /*
400  * We can only authenticate user requests which HAVE
401  * a User-Name attribute.
402  */
403  username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
404  if (!username) {
405  RDEBUG2("OpenDirectory requires a User-Name attribute");
407  }
408 
409  /* resolve SACL */
410  uuid_clear(guid_sacl);
411 
412  if (fr_perm_gid_from_str(request, &gid, kRadiusSACLName) < 0) {
413  RDEBUG2("The SACL group \"%s\" does not exist on this system", kRadiusSACLName);
414  } else {
415  err = mbr_gid_to_uuid(gid, guid_sacl);
416  if (err != 0) {
417  REDEBUG("The group \"%s\" does not have a GUID", kRadiusSACLName);
419  }
420  }
421 
422  /* resolve client access list */
423  uuid_clear(guid_nasgroup);
424 
425  client = client_from_request(request);
426 #if 0
427  if (client->community[0] != '\0' ) {
428  /*
429  * The "community" can be a GUID (Globally Unique ID) or
430  * a group name
431  */
432  if (uuid_parse(client->community, guid_nasgroup) != 0) {
433  /* attempt to resolve the name */
434  groupdata = getgrnam(client->community);
435  if (!groupdata) {
436  REDEBUG("The group \"%s\" does not exist on this system", client->community);
438  }
439  err = mbr_gid_to_uuid(groupdata->gr_gid, guid_nasgroup);
440  if (err != 0) {
441  REDEBUG("The group \"%s\" does not have a GUID", client->community);
443  }
444  }
445  }
446  else
447 #endif
448  {
449  if (!client) {
450  RDEBUG2("The client record could not be found for host %s",
451  fr_inet_ntoh(&request->packet->socket.inet.src_ipaddr, host_ipaddr, sizeof(host_ipaddr)));
452  } else {
453  RDEBUG2("The host %s does not have an access group",
454  fr_inet_ntoh(&request->packet->socket.inet.src_ipaddr, host_ipaddr, sizeof(host_ipaddr)));
455  }
456  }
457 
458  if (uuid_is_null(guid_sacl) && uuid_is_null(guid_nasgroup)) {
459  RDEBUG2("No access control groups, all users allowed");
460  goto setup_auth_type;
461  }
462 
463  /* resolve user */
464  uuid_clear(uuid);
465 
466  fr_perm_getpwnam(request, &userdata, username->vp_strvalue);
467  if (userdata != NULL) {
468  err = mbr_uid_to_uuid(userdata->pw_uid, uuid);
469  if (err != 0)
470  uuid_clear(uuid);
471  }
472  talloc_free(userdata);
473 
474  if (uuid_is_null(uuid)) {
475  REDEBUG("Could not get the user's uuid");
477  }
478 
479  if (!uuid_is_null(guid_sacl)) {
481  if (err != 0) {
482  REDEBUG("Failed to check group membership");
484  }
485 
486  if (ismember == 0) {
487  REDEBUG("User is not authorized");
489  }
490  }
491 
492  if (!uuid_is_null(guid_nasgroup)) {
493  err = mbr_check_membership_refresh(uuid, guid_nasgroup, &ismember);
494  if (err != 0) {
495  REDEBUG("Failed to check group membership");
497  }
498 
499  if (ismember == 0) {
500  REDEBUG("User is not authorized");
502  }
503  }
504 
505 setup_auth_type:
506  if (!inst->auth_type) {
507  WARN("No 'authenticate %s {...}' section or 'Auth-Type = %s' set. Cannot setup OpenDirectory authentication",
508  mctx->mi->name, mctx->mi->name);
510  }
511 
513 
515 }
516 
517 static int mod_instantiate(module_inst_ctx_t const *mctx)
518 {
519  rlm_opendirectory_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_opendirectory_t);
520 
521  inst->auth_type = fr_dict_enum_by_name(attr_auth_type, mctx->mi->name, -1);
522  if (!inst->auth_type) {
523  WARN("Failed to find 'authenticate %s {...}' section. OpenDirectory authentication will likely not work",
524  mctx->mi->name);
525  }
526 
527  return 0;
528 }
529 
530 /* globally exported name */
533  .common = {
534  .magic = MODULE_MAGIC_INIT,
535  .name = "opendirectory",
536  .inst_size = sizeof(rlm_opendirectory_t),
538  },
539  .method_group = {
540  .bindings = (module_method_binding_t[]){
541  { .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
542  { .section = SECTION_NAME("recv", CF_IDENT_ANY), .method = mod_authorize },
544  }
545  }
546 };
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 USES_APPLE_DEPRECATED_API
Definition: build.h:468
#define UNUSED
Definition: build.h:313
#define CF_IDENT_ANY
Definition: cf_util.h:78
static fr_slen_t err
Definition: dict.h:821
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
fr_dict_enum_value_t * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Definition: dict_util.c:3395
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
Value of an enumerated attribute.
Definition: dict.h:226
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:63
free(array)
char const * fr_inet_ntoh(fr_ipaddr_t const *src, char *out, size_t outlen)
Perform reverse resolution of an IP address.
Definition: inet.c:355
Describes a host allowed to send packets to the server.
Definition: client.h:80
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
Definition: log.h:335
talloc_free(reap)
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
unsigned int uint32_t
Definition: merged_model.c:33
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:427
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
int fr_perm_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name)
Resolve a username to a passwd entry.
Definition: perm.c:138
int fr_perm_gid_from_str(TALLOC_CTX *ctx, gid_t *out, char const *name)
Resolve a group name to a GID.
Definition: perm.c:345
#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
#define RETURN_MODULE_NOOP
Definition: rcode.h:62
#define RETURN_MODULE_INVALID
Definition: rcode.h:59
#define RETURN_MODULE_OK
Definition: rcode.h:57
#define RETURN_MODULE_DISALLOW
Definition: rcode.h:60
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_DISALLOW
Reject the request (user is locked out).
Definition: rcode.h:46
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition: rcode.h:41
#define RETURN_MODULE_NOTFOUND
Definition: rcode.h:61
static fr_dict_attr_t const * attr_user_password
static fr_dict_t const * dict_freeradius
fr_dict_enum_value_t * auth_type
static unlang_action_t mod_authenticate(rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
#define kRadiusSACLName
static fr_dict_t const * dict_radius
#define kRadiusServiceName
static fr_dict_attr_t const * attr_auth_type
int mbr_check_membership_refresh(uuid_t const user, uuid_t group, int *ismember)
static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
fr_dict_attr_autoload_t rlm_opendirectory_dict_attr[]
int mbr_check_service_membership(uuid_t const user, char const *servicename, int *ismember)
static fr_dict_attr_t const * attr_user_name
static long od_check_passwd(request_t *request, char const *uname, char const *password)
module_rlm_t rlm_opendirectory
fr_dict_autoload_t rlm_opendirectory_dict[]
static int mod_instantiate(module_inst_ctx_t const *mctx)
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
char const * name
Instance name e.g. user_database.
Definition: module.h:335
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
fr_client_t * client_from_request(request_t *request)
Search up a list of requests trying to locate one which has a client.
Definition: client.c:1112
RETURN_MODULE_FAIL
eap_aka_sim_process_conf_t * inst
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
int nonnull(2, 5))