21 RCSID(
"$Id: 46e7f6cb8b5332fb03cad7741ccd43e269a8d8e7 $")
24 #include <freeradius-devel/radiusd.h>
25 #include <freeradius-devel/modules.h>
26 #include <freeradius-devel/rad_assert.h>
27 #include <freeradius-devel/md5.h>
33 #include <DirectoryService/DirectoryService.h>
35 #define kActiveDirLoc "/Active Directory/"
41 char const*
name,
char const* value,
int len);
49 static rlm_rcode_t getUserNodeRef(
REQUEST *request,
char* inUserName,
char **outUserName,
50 tDirNodeReference* userNodeRef, tDirReference dsRef)
52 tDataBuffer *tDataBuff = NULL;
53 tDirNodeReference nodeRef = 0;
54 long status = eDSNoErr;
55 char const *what = NULL;
56 char *status_name = NULL;
57 tContextData context = 0;
58 uint32_t nodeCount = 0;
59 uint32_t attrIndex = 0;
60 tDataList *nodeName = NULL;
61 tAttributeEntryPtr pAttrEntry = NULL;
62 tDataList *pRecName = NULL;
63 tDataList *pRecType = NULL;
64 tDataList *pAttrType = NULL;
65 uint32_t recCount = 0;
66 tRecordEntry *pRecEntry = NULL;
67 tAttributeListRef attrListRef = 0;
68 char *pUserLocation = NULL;
69 tAttributeValueListRef valueRef = 0;
70 tDataList *pUserNode = NULL;
74 ERROR(
"rlm_mschap: getUserNodeRef(): no username");
78 tDataBuff = dsDataBufferAllocate(dsRef, 4096);
80 RERROR(
"Failed allocating buffer");
86 status = dsFindDirNodes(dsRef, tDataBuff, NULL,
87 eDSAuthenticationSearchNodeName,
88 &nodeCount, &context);
89 #define OPEN_DIR_ERROR(_x) do if (status != eDSNoErr) { \
94 OPEN_DIR_ERROR(
"Failed to find directory");
97 what =
"No directories found.";
101 status = dsGetDirNodeName(dsRef, tDataBuff, 1, &nodeName);
102 OPEN_DIR_ERROR(
"Failed getting directory name");
104 status = dsOpenDirNode(dsRef, nodeName, &nodeRef);
105 dsDataListDeallocate(dsRef, nodeName);
109 OPEN_DIR_ERROR(
"Failed opening directory");
111 pRecName = dsBuildListFromStrings(dsRef, inUserName, NULL);
112 pRecType = dsBuildListFromStrings(dsRef, kDSStdRecordTypeUsers,
114 pAttrType = dsBuildListFromStrings(dsRef,
115 kDSNAttrMetaNodeLocation,
116 kDSNAttrRecordName, NULL);
119 status = dsGetRecordList(nodeRef, tDataBuff, pRecName,
120 eDSExact, pRecType, pAttrType, 0,
121 &recCount, &context);
122 OPEN_DIR_ERROR(
"Failed getting record list");
125 what =
"No user records returned";
129 status = dsGetRecordEntry(nodeRef, tDataBuff, 1,
130 &attrListRef, &pRecEntry);
131 OPEN_DIR_ERROR(
"Failed getting record entry");
133 for (attrIndex = 1; (attrIndex <= pRecEntry->fRecordAttributeCount) && (status == eDSNoErr); attrIndex++) {
134 status = dsGetAttributeEntry(nodeRef, tDataBuff, attrListRef, attrIndex, &valueRef, &pAttrEntry);
135 if (status == eDSNoErr && pAttrEntry != NULL) {
136 tAttributeValueEntry *pValueEntry = NULL;
138 if (strcmp(pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation) == 0) {
139 status = dsGetAttributeValue(nodeRef, tDataBuff, 1, valueRef, &pValueEntry);
140 if (status == eDSNoErr && pValueEntry != NULL) {
141 pUserLocation = talloc_zero_array(request,
char, pValueEntry->fAttributeValueData.fBufferLength + 1);
142 memcpy(pUserLocation, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength);
144 }
else if (strcmp(pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName) == 0) {
145 status = dsGetAttributeValue(nodeRef, tDataBuff, 1, valueRef, &pValueEntry);
146 if (status == eDSNoErr && pValueEntry != NULL) {
147 *outUserName = talloc_array(request,
char, pValueEntry->fAttributeValueData.fBufferLength + 1);
148 memcpy(*outUserName, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength);
153 dsDeallocAttributeValueEntry(dsRef, pValueEntry);
157 dsDeallocAttributeEntry(dsRef, pAttrEntry);
159 dsCloseAttributeValueList(valueRef);
164 if (!pUserLocation) {
165 DEBUG2(
"[mschap] OpenDirectory has no user location");
174 if (strncmp(pUserLocation, kActiveDirLoc, strlen(kActiveDirLoc)) == 0) {
175 DEBUG2(
"[mschap] OpenDirectory authentication returning noop. OD doesn't support MSCHAPv2 for ActiveDirectory users");
180 pUserNode = dsBuildFromPath(dsRef, pUserLocation,
"/");
182 RERROR(
"Failed building user from path");
187 status = dsOpenDirNode(dsRef, pUserNode, userNodeRef);
188 dsDataListDeallocate(dsRef, pUserNode);
191 if (status != eDSNoErr) {
193 status_name = dsCopyDirStatusName(status);
194 RERROR(
"%s: status = %s", what, status_name);
204 if (pRecEntry != NULL)
205 dsDeallocRecordEntry(dsRef, pRecEntry);
207 if (tDataBuff != NULL)
208 dsDataBufferDeAllocate(dsRef, tDataBuff);
210 if (pUserLocation != NULL)
211 talloc_free(pUserLocation);
213 if (pRecName != NULL) {
214 dsDataListDeallocate(dsRef, pRecName);
217 if (pRecType != NULL) {
218 dsDataListDeallocate(dsRef, pRecType);
221 if (pAttrType != NULL) {
222 dsDataListDeallocate(dsRef, pAttrType);
226 dsCloseDirNode(nodeRef);
234 tDirStatus status = eDSNoErr;
235 tDirReference dsRef = 0;
236 tDirNodeReference userNodeRef = 0;
237 tDataBuffer *tDataBuff = NULL;
238 tDataBuffer *pStepBuff = NULL;
239 tDataNode *pAuthType = NULL;
242 char *username_string = NULL;
243 char *shortUserName = NULL;
250 username_string = talloc_array(request,
char, usernamepair->vp_length + 1);
251 if (!username_string)
254 strlcpy(username_string, usernamepair->vp_strvalue, usernamepair->vp_length + 1);
256 status = dsOpenDirService(&dsRef);
257 if (status != eDSNoErr) {
258 talloc_free(username_string);
259 RERROR(
"Failed opening directory service");
263 rcode = getUserNodeRef(request, username_string, &shortUserName, &userNodeRef, dsRef);
266 RDEBUG2(
"od_mschap_auth: getUserNodeRef() failed");
268 if (username_string != NULL)
269 talloc_free(username_string);
271 dsCloseDirService(dsRef);
297 pStepBuff = dsDataBufferAllocate(dsRef, 4096);
298 tDataBuff = dsDataBufferAllocate(dsRef, 4096);
299 pAuthType = dsDataNodeAllocateString(dsRef, kDSStdAuthMSCHAP2);
302 RDEBUG2(
"OD username_string = %s, OD shortUserName=%s (length = %lu)\n", username_string, shortUserName, strlen(shortUserName));
305 uiLen = (uint32_t)strlen(shortUserName);
306 memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen,
sizeof(uiLen));
307 uiCurr +=
sizeof(uiLen);
308 memcpy(&(tDataBuff->fBufferData[uiCurr]), shortUserName, uiLen);
312 RDEBUG2(
"Stepbuf server challenge : ");
313 for (t = 0; t < challenge->vp_length; t++) {
314 fprintf(stderr,
"%02x", challenge->vp_strvalue[t]);
316 fprintf(stderr,
"\n");
321 memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen,
sizeof(uiLen));
322 uiCurr +=
sizeof(uiLen);
323 memcpy(&(tDataBuff->fBufferData[uiCurr]), &(challenge->vp_strvalue[0]),
328 RDEBUG2(
"Stepbuf peer challenge : ");
329 for (t = 2; t < 18; t++) {
330 fprintf(stderr,
"%02x", response->vp_strvalue[t]);
332 fprintf(stderr,
"\n");
337 memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen,
sizeof(uiLen));
338 uiCurr +=
sizeof(uiLen);
339 memcpy(&(tDataBuff->fBufferData[uiCurr]), &(response->vp_strvalue[2]),
346 for (t = 26; t < 50; t++) {
347 fprintf(stderr,
"%02x", response->vp_strvalue[t]);
349 fprintf(stderr,
"\n");
354 memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen,
sizeof(uiLen));
355 uiCurr +=
sizeof(uiLen);
356 memcpy(&(tDataBuff->fBufferData[uiCurr]), &(response->vp_strvalue[26]),
361 uiLen = (uint32_t)strlen(username_string);
362 memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen,
sizeof(uiLen));
363 uiCurr +=
sizeof(uiLen);
364 memcpy(&(tDataBuff->fBufferData[uiCurr]), username_string, uiLen);
367 tDataBuff->fBufferLength = uiCurr;
369 status = dsDoDirNodeAuth(userNodeRef, pAuthType, 1, tDataBuff,
371 if (status == eDSNoErr) {
372 if (pStepBuff->fBufferLength > 4) {
375 memcpy(&len, pStepBuff->fBufferData,
sizeof(len));
377 char mschap_reply[42] = {
'\0' };
378 pStepBuff->fBufferData[len+4] =
'\0';
379 mschap_reply[0] =
'S';
380 mschap_reply[1] =
'=';
381 memcpy(&(mschap_reply[2]), &(pStepBuff->fBufferData[4]), len);
383 *response->vp_strvalue,
385 mschap_reply, len+2);
386 RDEBUG2(
"dsDoDirNodeAuth returns stepbuff: %s (len=%zu)\n", mschap_reply, len);
392 if (username_string != NULL)
393 talloc_free(username_string);
394 if (shortUserName != NULL)
395 talloc_free(shortUserName);
397 if (tDataBuff != NULL)
398 dsDataBufferDeAllocate(dsRef, tDataBuff);
399 if (pStepBuff != NULL)
400 dsDataBufferDeAllocate(dsRef, pStepBuff);
401 if (pAuthType != NULL)
402 dsDataNodeDeAllocate(dsRef, pAuthType);
403 if (userNodeRef != 0)
404 dsCloseDirNode(userNodeRef);
406 dsCloseDirService(dsRef);
408 if (status != eDSNoErr) {
409 char *status_name = dsCopyDirStatusName(status);
410 RERROR(
"rlm_mschap: authentication failed - status = %s", status_name);
#define RINDENT()
Indent R* messages by one level.
The module is OK, continue.
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
#define VENDORPEC_MICROSOFT
Immediately reject the request.
Stores an attribute, a value and various bits of other data.
RADIUS_PACKET * reply
Outgoing response.
#define REXDENT()
Exdent (unindent) R* messages by one level.
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
Module succeeded without doing anything.
Module failed, don't reply.
RADIUS_PACKET * packet
Incoming request.
void mschap_add_reply(REQUEST *request, unsigned char ident, char const *name, char const *value, size_t len)
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
size_t strlcpy(char *dst, char const *src, size_t siz)
#define PW_MSCHAP2_RESPONSE
#define USES_APPLE_DEPRECATED_API