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>
42 #include <sys/types.h>
45 #include <DirectoryService/DirectoryService.h>
46 #include <membership.h>
52 #ifndef HAVE_DECL_MBR_CHECK_SERVICE_MEMBERSHIP
55 #ifndef HAVE_DECL_MBR_CHECK_MEMBERSHIP_REFRESH
60 #define kRadiusSACLName "com.apple.access_radius"
61 #define kRadiusServiceName "radius"
93 long result = eDSAuthFailed;
94 tDirReference dsRef = 0;
95 tDataBuffer *tDataBuff;
96 tDirNodeReference nodeRef = 0;
97 long status = eDSNoErr;
101 tDataList *nodeName = NULL;
102 tAttributeEntryPtr pAttrEntry = NULL;
103 tDataList *pRecName = NULL;
104 tDataList *pRecType = NULL;
105 tDataList *pAttrType = NULL;
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;
122 if (!uname || !password)
127 status = dsOpenDirService( &dsRef );
128 if ( status != eDSNoErr )
131 tDataBuff = dsDataBufferAllocate( dsRef, 4096 );
136 status = dsFindDirNodes( dsRef, tDataBuff, NULL, eDSSearchNodeName, &nodeCount, &
context );
137 if (status != eDSNoErr || nodeCount < 1)
140 status = dsGetDirNodeName( dsRef, tDataBuff, 1, &nodeName );
141 if (status != eDSNoErr)
144 status = dsOpenDirNode( dsRef, nodeName, &nodeRef );
145 dsDataListDeallocate( dsRef, nodeName );
148 if (status != eDSNoErr)
151 pRecName = dsBuildListFromStrings( dsRef, uname, NULL );
152 pRecType = dsBuildListFromStrings( dsRef, kDSStdRecordTypeUsers, kDSStdRecordTypeComputers, kDSStdRecordTypeMachines, NULL );
153 pAttrType = dsBuildListFromStrings( dsRef, kDSNAttrMetaNodeLocation, kDSNAttrRecordName, kDSNAttrRecordType, NULL );
156 status = dsGetRecordList( nodeRef, tDataBuff, pRecName, eDSExact, pRecType,
157 pAttrType, 0, &recCount, &
context );
158 if ( status != eDSNoErr || recCount == 0 )
161 status = dsGetRecordEntry( nodeRef, tDataBuff, 1, &attrListRef, &pRecEntry );
162 if ( status != eDSNoErr )
165 for ( attrIndex = 1; (attrIndex <= pRecEntry->fRecordAttributeCount) && (status == eDSNoErr); attrIndex++ )
167 status = dsGetAttributeEntry( nodeRef, tDataBuff, attrListRef, attrIndex, &valueRef, &pAttrEntry );
168 if ( status == eDSNoErr && pAttrEntry != NULL )
170 if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
172 status = dsGetAttributeValue( nodeRef, tDataBuff, 1, valueRef, &pValueEntry );
173 if ( status == eDSNoErr && pValueEntry != NULL )
175 pUserLocation = talloc_zero_array(request,
char, pValueEntry->fAttributeValueData.fBufferLength + 1);
176 memcpy( pUserLocation, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength );
180 if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
182 status = dsGetAttributeValue( nodeRef, tDataBuff, 1, valueRef, &pValueEntry );
183 if ( status == eDSNoErr && pValueEntry != NULL )
185 pUserName = talloc_zero_array(request,
char, pValueEntry->fAttributeValueData.fBufferLength + 1);
186 memcpy( pUserName, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength );
190 if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordType ) == 0 )
192 status = dsGetAttributeValue( nodeRef, tDataBuff, 1, valueRef, &pValueEntry );
193 if ( status == eDSNoErr && pValueEntry != NULL )
195 pRecordType = pValueEntry;
200 if ( pValueEntry != NULL ) {
201 dsDeallocAttributeValueEntry( dsRef, pValueEntry );
204 if ( pAttrEntry != NULL ) {
205 dsDeallocAttributeEntry( dsRef, pAttrEntry );
208 dsCloseAttributeValueList( valueRef );
213 pUserNode = dsBuildFromPath( dsRef, pUserLocation,
"/" );
214 status = dsOpenDirNode( dsRef, pUserNode, &userNodeRef );
215 dsDataListDeallocate( dsRef, pUserNode );
218 if ( status != eDSNoErr )
221 pStepBuff = dsDataBufferAllocate( dsRef, 128 );
223 pAuthType = dsDataNodeAllocateString( dsRef, kDSStdAuthNodeNativeClearTextOK );
227 RDEBUG2(
"Failed to find 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 );
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 );
245 tDataBuff->fBufferLength = uiCurr;
247 result = dsDoDirNodeAuthOnRecordType( userNodeRef, pAuthType, 1, tDataBuff, pStepBuff, NULL, &pRecordType->fAttributeValueData );
252 if (pAuthType != NULL) {
253 dsDataNodeDeAllocate( dsRef, pAuthType );
256 if (pRecordType != NULL) {
257 dsDeallocAttributeValueEntry( dsRef, pRecordType );
260 if (tDataBuff != NULL) {
261 bzero( tDataBuff, tDataBuff->fBufferSize );
262 dsDataBufferDeAllocate( dsRef, tDataBuff );
265 if (pStepBuff != NULL) {
266 dsDataBufferDeAllocate( dsRef, pStepBuff );
269 if (pUserLocation != NULL) {
271 pUserLocation = NULL;
273 if (pUserName != NULL) {
277 if (pRecName != NULL) {
278 dsDataListDeallocate( dsRef, pRecName );
282 if (pRecType != NULL) {
283 dsDataListDeallocate( dsRef, pRecType );
287 if (pAttrType != NULL) {
288 dsDataListDeallocate( dsRef, pAttrType );
293 dsCloseDirNode(nodeRef);
297 dsCloseDirService(dsRef);
312 long odResult = eDSAuthFailed;
323 REDEBUG(
"Attribute \"User-Name\" is required for authentication");
328 REDEBUG(
"Attribute \"User-Password\" is required for authentication");
335 if (password->vp_length == 0) {
336 REDEBUG(
"User-Password must not be empty");
344 RDEBUG(
"Login attempt with password \"%pV\"", &password->data);
346 RDEBUG2(
"Login attempt with password");
350 password->vp_strvalue);
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:
388 struct passwd *userdata = NULL;
393 uuid_t guid_nasgroup;
395 char host_ipaddr[128] = {0};
405 RDEBUG2(
"OpenDirectory requires a User-Name attribute");
410 uuid_clear(guid_sacl);
415 err = mbr_gid_to_uuid(gid, guid_sacl);
423 uuid_clear(guid_nasgroup);
427 if (client->community[0] !=
'\0' ) {
432 if (uuid_parse(client->community, guid_nasgroup) != 0) {
434 groupdata = getgrnam(client->community);
436 REDEBUG(
"The group \"%s\" does not exist on this system", client->community);
439 err = mbr_gid_to_uuid(groupdata->gr_gid, guid_nasgroup);
441 REDEBUG(
"The group \"%s\" does not have a GUID", client->community);
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)));
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)));
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;
467 if (userdata != NULL) {
468 err = mbr_uid_to_uuid(userdata->pw_uid, uuid);
474 if (uuid_is_null(uuid)) {
475 REDEBUG(
"Could not get the user's uuid");
479 if (!uuid_is_null(guid_sacl)) {
482 REDEBUG(
"Failed to check group membership");
487 REDEBUG(
"User is not authorized");
492 if (!uuid_is_null(guid_nasgroup)) {
495 REDEBUG(
"Failed to check group membership");
500 REDEBUG(
"User is not authorized");
506 if (!
inst->auth_type) {
507 WARN(
"No 'authenticate %s {...}' section or 'Auth-Type = %s' set. Cannot setup OpenDirectory authentication",
522 if (!
inst->auth_type) {
523 WARN(
"Failed to find 'authenticate %s {...}' section. OpenDirectory authentication will likely not work",
535 .name =
"opendirectory",
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
#define USES_APPLE_DEPRECATED_API
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
fr_dict_enum_value_t * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
Value of an enumerated attribute.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
char const * fr_inet_ntoh(fr_ipaddr_t const *src, char *out, size_t outlen)
Perform reverse resolution of an IP address.
Describes a host allowed to send packets to the server.
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
module_instance_t const * mi
Instance of the module being instantiated.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for instantiation calls.
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.
module_t common
Common fields presented by all modules.
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.
int fr_perm_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name)
Resolve a username to a passwd entry.
int fr_perm_gid_from_str(TALLOC_CTX *ctx, gid_t *out, char const *name)
Resolve a group name to a GID.
#define RETURN_MODULE_NOOP
#define RETURN_MODULE_INVALID
#define RETURN_MODULE_DISALLOW
rlm_rcode_t
Return codes indicating the result of the module call.
@ RLM_MODULE_OK
The module is OK, continue.
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
@ RLM_MODULE_REJECT
Immediately reject the request.
#define RETURN_MODULE_NOTFOUND
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)
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)
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
char const * name
Instance name e.g. user_database.
void * data
Module's instance data.
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Named methods exported by a module.
fr_client_t * client_from_request(request_t *request)
Search up a list of requests trying to locate one which has a client.
eap_aka_sim_process_conf_t * inst
Stores an attribute, a value and various bits of other data.
#define talloc_get_type_abort_const