Пример #1
0
int rad_check_ts(UNUSED uint32_t nasaddr, UNUSED unsigned int portnum,
		 UNUSED const char *user, UNUSED const char *session_id)
{
	radlog(L_ERR, "Simultaneous-Use is not supported");
	return 2;
}
Пример #2
0
/*
 * given a radius request with many attribues in the EAP-SIM range, build
 * them all into a single EAP-SIM body.
 *
 */
int map_eapsim_basictypes(RADIUS_PACKET *r, EAP_PACKET *ep)
{
	VALUE_PAIR       *vp;
	int               encoded_size;
	uint8_t          *encodedmsg, *attr;
	unsigned int      id, eapcode;
	unsigned char    *macspace, *append;
	int               appendlen;
	unsigned char     subtype;

	macspace = NULL;
	append = NULL;
	appendlen = 0;

	/*
	 * encodedmsg is now an EAP-SIM message.
	 * it might be too big for putting into an EAP-Type-SIM
	 *
	 */
	vp = pairfind(r->vps, ATTRIBUTE_EAP_SIM_SUBTYPE, 0);
	if(vp == NULL)
	{
		subtype = eapsim_start;
	}
	else
	{
		subtype = vp->vp_integer;
	}

	vp = pairfind(r->vps, ATTRIBUTE_EAP_ID, 0);
	if(vp == NULL)
	{
		id = ((int)getpid() & 0xff);
	}
	else
	{
		id = vp->vp_integer;
	}

	vp = pairfind(r->vps, ATTRIBUTE_EAP_CODE, 0);
	if(vp == NULL)
	{
		eapcode = PW_EAP_REQUEST;
	}
	else
	{
		eapcode = vp->vp_integer;
	}


	/*
	 * take a walk through the attribute list to see how much space
	 * that we need to encode all of this.
	 */
	encoded_size = 0;
	for(vp = r->vps; vp != NULL; vp = vp->next)
	{
		int roundedlen;
		int vplen;

		if(vp->attribute < ATTRIBUTE_EAP_SIM_BASE ||
		   vp->attribute >= ATTRIBUTE_EAP_SIM_BASE+256)
		{
			continue;
		}

		vplen = vp->length;

		/*
		 * the AT_MAC attribute is a bit different, when we get to this
		 * attribute, we pull the contents out, save it for later
		 * processing, set the size to 16 bytes (plus 2 bytes padding).
		 *
 		 * At this point, we only care about the size.
		 */
		if(vp->attribute == ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC) {
			vplen = 18;
		}

		/* round up to next multiple of 4, after taking in
		 * account the type and length bytes
		 */
		roundedlen = (vplen + 2 + 3) & ~3;
		encoded_size += roundedlen;
	}

	if (ep->code != PW_EAP_SUCCESS)
		ep->code = eapcode;
	ep->id = (id & 0xff);
	ep->type.type = PW_EAP_SIM;

	/*
	 * if no attributes were found, do very little.
	 *
	 */
	if(encoded_size == 0)
	{
	        encodedmsg = malloc(3);
		/* FIX: could be NULL */

		encodedmsg[0]=subtype;
		encodedmsg[1]=0;
		encodedmsg[2]=0;

		ep->type.length = 3;
		ep->type.data = encodedmsg;

		return 0;
	}


	/*
	 * figured out the length, so malloc some space for the results.
	 *
	 * Note that we do not bother going through an "EAP" stage, which
	 * is a bit strange compared to the unmap, which expects to see
	 * an EAP-SIM virtual attributes.
	 *
	 * EAP is 1-code, 1-identifier, 2-length, 1-type = 5 overhead.
	 *
	 * SIM code adds a subtype, and 2 bytes of reserved = 3.
	 *
	 */

	/* malloc space for it */

	encoded_size += 3;
	encodedmsg = malloc(encoded_size);
	if (encodedmsg == NULL) {
		radlog(L_ERR, "eapsim: out of memory allocating %d bytes", encoded_size+5);
		return 0;
	}
	memset(encodedmsg, 0, encoded_size);

	/*
	 * now walk the attributes again, sticking them in.
	 *
	 * we go three bytes into the encoded message, because there are two
	 * bytes of reserved, and we will fill the "subtype" in later.
	 *
	 */
	attr = encodedmsg+3;

	for(vp = r->vps; vp != NULL; vp = vp->next)
	{
		int roundedlen;

		if(vp->attribute < ATTRIBUTE_EAP_SIM_BASE ||
		   vp->attribute >= ATTRIBUTE_EAP_SIM_BASE+256)
		{
			continue;
		}

		/*
		 * the AT_MAC attribute is a bit different, when we get to this
		 * attribute, we pull the contents out, save it for later
		 * processing, set the size to 16 bytes (plus 2 bytes padding).
		 *
 		 * At this point, we put in zeros, and remember where the
		 * sixteen bytes go.
		 */
		if(vp->attribute == ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC) {
			roundedlen = 20;
			memset(&attr[2], 0, 18);
			macspace = &attr[4];
			append = vp->vp_octets;
			appendlen = vp->length;
		}
		else {
			roundedlen = (vp->length + 2 + 3) & ~3;
			memset(attr, 0, roundedlen);
			memcpy(&attr[2], vp->vp_strvalue, vp->length);
		}
		attr[0] = vp->attribute - ATTRIBUTE_EAP_SIM_BASE;
		attr[1] = roundedlen >> 2;

		attr += roundedlen;
	}

	encodedmsg[0] = subtype;

	ep->type.length = encoded_size;
	ep->type.data = encodedmsg;

	/*
	 * if macspace was set and we have a key,
	 * then we should calculate the HMAC-SHA1 of the resulting EAP-SIM
	 * packet, appended with the value of append.
	 */
	vp = pairfind(r->vps, ATTRIBUTE_EAP_SIM_KEY, 0);
	if(macspace != NULL && vp != NULL)
	{
		unsigned char   *buffer;
		eap_packet_t	*hdr;
		uint16_t         hmaclen, total_length = 0;
		unsigned char    sha1digest[20];

		total_length = EAP_HEADER_LEN + 1 + encoded_size;
		hmaclen = total_length + appendlen;
		buffer = (unsigned char *)malloc(hmaclen);
		hdr = (eap_packet_t *)buffer;
		if (!hdr) {
			radlog(L_ERR, "rlm_eap: out of memory");
			free(encodedmsg);
			return 0;
		}

		hdr->code = eapcode & 0xFF;
		hdr->id = (id & 0xFF);
		total_length = htons(total_length);
		memcpy(hdr->length, &total_length, sizeof(total_length));

		hdr->data[0] = PW_EAP_SIM;

		/* copy the data */
		memcpy(&hdr->data[1], encodedmsg, encoded_size);

		/* copy the nonce */
		memcpy(&hdr->data[encoded_size+1], append, appendlen);

		/* HMAC it! */
		fr_hmac_sha1(buffer, hmaclen,
			       vp->vp_octets, vp->length,
			       sha1digest);

		/* done with the buffer, free it */
		free(buffer);

		/* now copy the digest to where it belongs in the AT_MAC */
                /* note that it is truncated to 128-bits */
		memcpy(macspace, sha1digest, 16);
	}

	/* if we had an AT_MAC and no key, then fail */
	if(macspace != NULL && vp == NULL)
	{
		if(encodedmsg != NULL)
			free(encodedmsg);
		return 0;
	}

	return 1;
}
/*
 *	Initiate the EAP-MSCHAPV2 session by sending a challenge to the peer.
 */
static int mschapv2_initiate(void *type_data, EAP_HANDLER *handler)
{
	int		i;
	VALUE_PAIR	*challenge;
	mschapv2_opaque_t *data;

	type_data = type_data;	/* -Wunused */

	challenge = pairmake("MS-CHAP-Challenge", "0x00", T_OP_EQ);
	if (!challenge) {
		radlog(L_ERR, "rlm_eap_mschapv2: out of memory");
		return 0;
	}

	/*
	 *	Get a random challenge.
	 */
	challenge->length = MSCHAPV2_CHALLENGE_LEN;
	for (i = 0; i < MSCHAPV2_CHALLENGE_LEN; i++) {
		challenge->vp_strvalue[i] = fr_rand();
	}
	DEBUG2("rlm_eap_mschapv2: Issuing Challenge");

	/*
	 *	Keep track of the challenge.
	 */
	data = malloc(sizeof(mschapv2_opaque_t));
	rad_assert(data != NULL);

	/*
	 *	We're at the stage where we're challenging the user.
	 */
	data->code = PW_EAP_MSCHAPV2_CHALLENGE;
	memcpy(data->challenge, challenge->vp_strvalue, MSCHAPV2_CHALLENGE_LEN);
	data->mppe_keys = NULL;
	data->reply = NULL;

	handler->opaque = data;
	handler->free_opaque = free_data;

	/*
	 *	Compose the EAP-MSCHAPV2 packet out of the data structure,
	 *	and free it.
	 */
	eapmschapv2_compose(handler, challenge);
	pairfree(&challenge);

#ifdef WITH_PROXY
	/*
	 *	The EAP session doesn't have enough information to
	 *	proxy the "inside EAP" protocol.  Disable EAP proxying.
	 */
	handler->request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
#endif

	/*
	 *	We don't need to authorize the user at this point.
	 *
	 *	We also don't need to keep the challenge, as it's
	 *	stored in 'handler->eap_ds', which will be given back
	 *	to us...
	 */
	handler->stage = AUTHENTICATE;

	return 1;
}
Пример #4
0
static int getUserNodeRef(char* inUserName, char **outUserName,
			  tDirNodeReference* userNodeRef, tDirReference dsRef)
{
	tDataBuffer             *tDataBuff	= NULL;
	tDirNodeReference       nodeRef		= 0;
	long                    status		= eDSNoErr;
	tContextData            context		= 0;
	uint32_t           	nodeCount	= 0;
	uint32_t                attrIndex	= 0;
	tDataList               *nodeName	= NULL;
	tAttributeEntryPtr      pAttrEntry	= NULL;
	tDataList               *pRecName	= NULL;
	tDataList               *pRecType	= NULL;
	tDataList               *pAttrType	= NULL;
	uint32_t           	recCount	= 0;
	tRecordEntry            *pRecEntry	= NULL;
	tAttributeListRef       attrListRef	= 0;
	char                    *pUserLocation	= NULL;
	tAttributeValueListRef  valueRef	= 0;
	tAttributeValueEntry    *pValueEntry	= NULL;
	tDataList               *pUserNode	= NULL;
	int                     result		= RLM_MODULE_FAIL;
	
	if (inUserName == NULL) {
		radlog(L_ERR, "rlm_mschap: getUserNodeRef(): no username");
		return RLM_MODULE_FAIL;
	}
    
	tDataBuff = dsDataBufferAllocate(dsRef, 4096);
	if (tDataBuff == NULL) {
		radlog(L_ERR, "rlm_mschap: getUserNodeRef(): dsDataBufferAllocate() status = %ld", status);  
		return RLM_MODULE_FAIL;
	}
	
	do {
		/* find on search node */
		status = dsFindDirNodes(dsRef, tDataBuff, NULL,
					eDSAuthenticationSearchNodeName,
					&nodeCount, &context);
		if (status != eDSNoErr) {
			radlog(L_ERR,"rlm_mschap: getUserNodeRef(): no node found? status = %ld", status);  
			result = RLM_MODULE_FAIL;
			break;
		}
		if (nodeCount < 1) {
			radlog(L_ERR,"rlm_mschap: getUserNodeRef(): nodeCount < 1, status = %ld", status);  
			result = RLM_MODULE_FAIL;
			break;
		}
		
		status = dsGetDirNodeName(dsRef, tDataBuff, 1, &nodeName);
		if (status != eDSNoErr) {
			radlog(L_ERR,"rlm_mschap: getUserNodeRef(): dsGetDirNodeName() status = %ld", status);  
			result = RLM_MODULE_FAIL;
			break;
		}
		
		status = dsOpenDirNode(dsRef, nodeName, &nodeRef);
		dsDataListDeallocate(dsRef, nodeName);
		free(nodeName);
		nodeName = NULL;
		
		if (status != eDSNoErr) {
			radlog(L_ERR,"rlm_mschap: getUserNodeRef(): dsOpenDirNode() status = %ld", status);  
			result = RLM_MODULE_FAIL;
			break;
		}
		
		pRecName = dsBuildListFromStrings(dsRef, inUserName, NULL);
		pRecType = dsBuildListFromStrings(dsRef, kDSStdRecordTypeUsers,
						  NULL);
		pAttrType = dsBuildListFromStrings(dsRef,
						   kDSNAttrMetaNodeLocation,
						   kDSNAttrRecordName, NULL);
		
		recCount = 1;
		status = dsGetRecordList(nodeRef, tDataBuff, pRecName,
					 eDSExact, pRecType, pAttrType, 0,
					 &recCount, &context);
		if (status != eDSNoErr || recCount == 0) {
			radlog(L_ERR,"rlm_mschap: getUserNodeRef(): dsGetRecordList() status = %ld, recCount=%u", status, recCount);
			result = RLM_MODULE_FAIL;
			break;
		}
		
		status = dsGetRecordEntry(nodeRef, tDataBuff, 1,
					  &attrListRef, &pRecEntry);
		if (status != eDSNoErr) {
			radlog(L_ERR,"rlm_mschap: getUserNodeRef(): dsGetRecordEntry() status = %ld", status);  
			result = RLM_MODULE_FAIL;
			break;	
		}
		
		for (attrIndex = 1; (attrIndex <= pRecEntry->fRecordAttributeCount) && (status == eDSNoErr); attrIndex++) {
			status = dsGetAttributeEntry(nodeRef, tDataBuff, attrListRef, attrIndex, &valueRef, &pAttrEntry);
			if (status == eDSNoErr && pAttrEntry != NULL) {
				if (strcmp(pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation) == 0) {
					status = dsGetAttributeValue(nodeRef, tDataBuff, 1, valueRef, &pValueEntry);
					if (status == eDSNoErr && pValueEntry != NULL) {
						pUserLocation = (char *) calloc(pValueEntry->fAttributeValueData.fBufferLength + 1, sizeof(char));
						memcpy(pUserLocation, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength);
					}
				} else if (strcmp(pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName) == 0) {
					status = dsGetAttributeValue(nodeRef, tDataBuff, 1, valueRef, &pValueEntry);
					if (status == eDSNoErr && pValueEntry != NULL) {
						*outUserName = (char *) malloc(pValueEntry->fAttributeValueData.fBufferLength + 1);
						bzero(*outUserName,pValueEntry->fAttributeValueData.fBufferLength + 1);
						memcpy(*outUserName, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength);
					}
				}
				
				if (pValueEntry != NULL) {
					dsDeallocAttributeValueEntry(dsRef, pValueEntry);
					pValueEntry = NULL;
				}
				
				dsDeallocAttributeEntry(dsRef, pAttrEntry);
				pAttrEntry = NULL;
				dsCloseAttributeValueList(valueRef);
				valueRef = 0;
			}
		}
		
		/* OpenDirectory doesn't support mschapv2 authentication against
		 * Active Directory.  AD users need to be authenticated using the
		 * normal freeradius AD path (i.e. ntlm_auth).
		 */
		if (strncmp(pUserLocation, kActiveDirLoc, strlen(kActiveDirLoc)) == 0) {
			DEBUG2("[mschap] OpenDirectory authentication returning noop.  OD doesn't support MSCHAPv2 for ActiveDirectory users.");
			result = RLM_MODULE_NOOP;
			break;
		}
        
		pUserNode = dsBuildFromPath(dsRef, pUserLocation, "/");
		if (pUserNode == NULL) {
			radlog(L_ERR,"rlm_mschap: getUserNodeRef(): dsBuildFromPath() returned NULL");  
			result = RLM_MODULE_FAIL;
			break;
		}
		
		status = dsOpenDirNode(dsRef, pUserNode, userNodeRef);
		dsDataListDeallocate(dsRef, pUserNode);
		free(pUserNode);

		if (status != eDSNoErr) {
			radlog(L_ERR,"rlm_mschap: getUserNodeRef(): dsOpenDirNode() status = %ld", status);  
			result = RLM_MODULE_FAIL;
			break;
		}
		
		result = RLM_MODULE_OK;
	}
	while (0);
	
	if (pRecEntry != NULL)
		dsDeallocRecordEntry(dsRef, pRecEntry);

	if (tDataBuff != NULL)
		dsDataBufferDeAllocate(dsRef, tDataBuff);
		
	if (pUserLocation != NULL)
		free(pUserLocation);
		
	if (pRecName != NULL) {
		dsDataListDeallocate(dsRef, pRecName);
		free(pRecName);
	}
	if (pRecType != NULL) {
		dsDataListDeallocate(dsRef, pRecType);
		free(pRecType);
	}
	if (pAttrType != NULL) {
		dsDataListDeallocate(dsRef, pAttrType);
		free(pAttrType);
	}
	if (nodeRef != 0)
		dsCloseDirNode(nodeRef);
	
	return  result;
}
Пример #5
0
static int
eap_pwd_authenticate (void *arg, EAP_HANDLER *handler)
{
    pwd_session_t *pwd_session;
    pwd_hdr *hdr;
    pwd_id_packet *id;
    EAP_PACKET *response;
    REQUEST *request, *fake;
    VALUE_PAIR *pw, **outvps, *vp;
    EAP_DS *eap_ds;
    int len, ret = 0;
    eap_pwd_t *inst = (eap_pwd_t *)arg;
    uint16_t offset;
    uint8_t exch, *buf, *ptr, msk[MSK_EMSK_LEN], emsk[MSK_EMSK_LEN];
    uint8_t peer_confirm[SHA256_DIGEST_LENGTH];
    BIGNUM *x = NULL, *y = NULL;

    if ((handler == NULL) ||
            ((eap_ds = handler->eap_ds) == NULL) ||
            (inst == NULL)) {
        return 0;
    }
    pwd_session = (pwd_session_t *)handler->opaque;
    request = handler->request;
    response = handler->eap_ds->response;
    hdr = (pwd_hdr *)response->type.data;

    buf = hdr->data;
    len = response->type.length - sizeof(pwd_hdr);

    /*
     * see if we're fragmenting, if so continue until we're done
     */
    if (pwd_session->out_buf_pos) {
        if (len) {
            RDEBUG2("pwd got something more than an ACK for a fragment");
        }
        return send_pwd_request(pwd_session, eap_ds);
    }

    /*
     * the first fragment will have a total length, make a
     * buffer to hold all the fragments
     */
    if (EAP_PWD_GET_LENGTH_BIT(hdr)) {
        if (pwd_session->in_buf) {
            RDEBUG2("pwd already alloced buffer for fragments");
            return 0;
        }
        pwd_session->in_buf_len = ntohs(buf[0] * 256 | buf[1]);
        if ((pwd_session->in_buf = malloc(pwd_session->in_buf_len)) == NULL) {
            RDEBUG2("pwd cannot malloc %d buffer to hold fragments",
                    pwd_session->in_buf_len);
            return 0;
        }
        memset(pwd_session->in_buf, 0, pwd_session->in_buf_len);
        pwd_session->in_buf_pos = 0;
        buf += sizeof(uint16_t);
        len -= sizeof(uint16_t);
    }

    /*
     * all fragments, including the 1st will have the M(ore) bit set,
     * buffer those fragments!
     */
    if (EAP_PWD_GET_MORE_BIT(hdr)) {
        rad_assert(pwd_session->in_buf != NULL);
        if ((pwd_session->in_buf_pos + len) > pwd_session->in_buf_len) {
            RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent.");
            return 0;
        }
        memcpy(pwd_session->in_buf + pwd_session->in_buf_pos, buf, len);
        pwd_session->in_buf_pos += len;

        /*
         * send back an ACK for this fragment
         */
        exch = EAP_PWD_GET_EXCHANGE(hdr);
        eap_ds->request->code = PW_EAP_REQUEST;
        eap_ds->request->type.type = PW_EAP_PWD;
        eap_ds->request->type.length = sizeof(pwd_hdr);
        if ((eap_ds->request->type.data = malloc(sizeof(pwd_hdr))) == NULL) {
            radlog(L_ERR, "rlm_eap_pwd: fragment ACK, out of memory");
            return 0;
        }
        hdr = (pwd_hdr *)eap_ds->request->type.data;
        EAP_PWD_SET_EXCHANGE(hdr, exch);
        return 1;

    }

    if (pwd_session->in_buf) {
        /*
         * the last fragment...
         */
        if ((pwd_session->in_buf_pos + len) > pwd_session->in_buf_len) {
            RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent.");
            return 0;
        }
        memcpy(pwd_session->in_buf + pwd_session->in_buf_pos, buf, len);
        buf = pwd_session->in_buf;
        len = pwd_session->in_buf_len;
    }

    switch (pwd_session->state) {
    case PWD_STATE_ID_REQ:
        if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_ID) {
            RDEBUG2("pwd exchange is incorrect: not ID");
            return 0;
        }
        id = (pwd_id_packet *)buf;
        if ((id->prf != EAP_PWD_DEF_PRF) ||
                (id->random_function != EAP_PWD_DEF_RAND_FUN) ||
                (id->prep != EAP_PWD_PREP_NONE) ||
                (memcmp(id->token, (char *)&pwd_session->token, 4)) ||
                (id->group_num != ntohs(pwd_session->group_num))) {
            RDEBUG2("pwd id response is invalid");
            return 0;
        }
        /*
         * we've agreed on the ciphersuite, record it...
         */
        ptr = (uint8_t *)&pwd_session->ciphersuite;
        memcpy(ptr, (char *)&id->group_num, sizeof(uint16_t));
        ptr += sizeof(uint16_t);
        *ptr = EAP_PWD_DEF_RAND_FUN;
        ptr += sizeof(uint8_t);
        *ptr = EAP_PWD_DEF_PRF;

        pwd_session->peer_id_len = len - sizeof(pwd_id_packet);
        if (pwd_session->peer_id_len >= sizeof(pwd_session->peer_id)) {
            RDEBUG2("pwd id response is malformed");
            return 0;
        }
        memcpy(pwd_session->peer_id, id->identity,
               pwd_session->peer_id_len);
        pwd_session->peer_id[pwd_session->peer_id_len] = '\0';

        /*
         * make fake request to get the password for the usable ID
         */
        if ((fake = request_alloc_fake(handler->request)) == NULL) {
            RDEBUG("pwd unable to create fake request!");
            return 0;
        }
        if ((fake->username = pairmake("User-Name", "", T_OP_EQ)) == NULL) {
            RDEBUG("pwd unanable to create value pair for username!");
            request_free(&fake);
            return 0;
        }
        memcpy(fake->username->vp_strvalue, pwd_session->peer_id,
               pwd_session->peer_id_len);
        fake->username->length = pwd_session->peer_id_len;
        fake->username->vp_strvalue[fake->username->length] = 0;

        if ((vp = pairfind(request->config_items, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) {
            fake->server = vp->vp_strvalue;

        } else if (inst->conf->virtual_server) {
            fake->server = inst->conf->virtual_server;

        } /* else fake->server == request->server */

        if ((debug_flag > 0) && fr_log_fp) {
            RDEBUG("Sending tunneled request");

            debug_pair_list(fake->packet->vps);

            fprintf(fr_log_fp, "server %s {\n",
                    (fake->server == NULL) ? "" : fake->server);
        }

        /*
         *	Call authorization recursively, which will
         *	get the password.
         */
        module_authorize(0, fake);

        /*
         *	Note that we don't do *anything* with the reply
         *	attributes.
         */
        if ((debug_flag > 0) && fr_log_fp) {
            fprintf(fr_log_fp, "} # server %s\n",
                    (fake->server == NULL) ? "" : fake->server);

            RDEBUG("Got tunneled reply code %d", fake->reply->code);

            debug_pair_list(fake->reply->vps);
        }

        if ((pw = pairfind(fake->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) == NULL) {
            DEBUG2("failed to find password for %s to do pwd authentication",
                   pwd_session->peer_id);
            request_free(&fake);
            return 0;
        }

        if (compute_password_element(pwd_session, pwd_session->group_num,
                                     pw->data.strvalue, strlen(pw->data.strvalue),
                                     inst->conf->server_id, strlen(inst->conf->server_id),
                                     pwd_session->peer_id, strlen(pwd_session->peer_id),
                                     &pwd_session->token)) {
            DEBUG2("failed to obtain password element :-(");
            request_free(&fake);
            return 0;
        }
        request_free(&fake);

        /*
         * compute our scalar and element
         */
        if (compute_scalar_element(pwd_session, inst->bnctx)) {
            DEBUG2("failed to compute server's scalar and element");
            return 0;
        }
        if (((x = BN_new()) == NULL) ||
                ((y = BN_new()) == NULL)) {
            DEBUG2("server point allocation failed");
            return 0;
        }
        /*
         * element is a point, get both coordinates: x and y
         */
        if (!EC_POINT_get_affine_coordinates_GFp(pwd_session->group,
                pwd_session->my_element, x, y,
                inst->bnctx)) {
            DEBUG2("server point assignment failed");
            BN_free(x);
            BN_free(y);
            return 0;
        }
        /*
         * construct request
         */
        pwd_session->out_buf_len = BN_num_bytes(pwd_session->order) +
                                   (2 * BN_num_bytes(pwd_session->prime));
        if ((pwd_session->out_buf = malloc(pwd_session->out_buf_len)) == NULL) {
            radlog(L_ERR, "rlm_eap_pwd: out of memory to send commit");
            return 0;
        }
        memset(pwd_session->out_buf, 0, pwd_session->out_buf_len);

        ptr = pwd_session->out_buf;
        offset = BN_num_bytes(pwd_session->prime) - BN_num_bytes(x);
        BN_bn2bin(x, ptr + offset);

        ptr += BN_num_bytes(pwd_session->prime);
        offset = BN_num_bytes(pwd_session->prime) - BN_num_bytes(y);
        BN_bn2bin(y, ptr + offset);

        ptr += BN_num_bytes(pwd_session->prime);
        offset = BN_num_bytes(pwd_session->order) - BN_num_bytes(pwd_session->my_scalar);
        BN_bn2bin(pwd_session->my_scalar, ptr + offset);

        pwd_session->state = PWD_STATE_COMMIT;
        ret = send_pwd_request(pwd_session, eap_ds);
        break;
    case PWD_STATE_COMMIT:
        if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_COMMIT) {
            RDEBUG2("pwd exchange is incorrect: not commit!");
            return 0;
        }
        /*
         * process the peer's commit and generate the shared key, k
         */
        if (process_peer_commit(pwd_session, buf, inst->bnctx)) {
            RDEBUG2("failed to process peer's commit");
            return 0;
        }

        /*
         * compute our confirm blob
         */
        if (compute_server_confirm(pwd_session, pwd_session->my_confirm, inst->bnctx)) {
            radlog(L_ERR, "rlm_eap_pwd: failed to compute confirm!");
            return 0;
        }
        /*
         * construct a response...which is just our confirm blob
         */
        pwd_session->out_buf_len = SHA256_DIGEST_LENGTH;
        if ((pwd_session->out_buf = malloc(pwd_session->out_buf_len)) == NULL) {
            radlog(L_ERR, "rlm_eap_pwd: out of memory to send confirm");
            return 0;
        }
        memset(pwd_session->out_buf, 0, pwd_session->out_buf_len);
        memcpy(pwd_session->out_buf, pwd_session->my_confirm, SHA256_DIGEST_LENGTH);

        pwd_session->state = PWD_STATE_CONFIRM;
        ret = send_pwd_request(pwd_session, eap_ds);
        break;
    case PWD_STATE_CONFIRM:
        if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_CONFIRM) {
            RDEBUG2("pwd exchange is incorrect: not commit!");
            return 0;
        }
        if (compute_peer_confirm(pwd_session, peer_confirm, inst->bnctx)) {
            RDEBUG2("pwd exchange cannot compute peer's confirm");
            return 0;
        }
        if (memcmp(peer_confirm, buf, SHA256_DIGEST_LENGTH)) {
            RDEBUG2("pwd exchange fails: peer confirm is incorrect!");
            return 0;
        }
        if (compute_keys(pwd_session, peer_confirm, msk, emsk)) {
            RDEBUG2("pwd exchange cannot generate (E)MSK!");
            return 0;
        }
        eap_ds->request->code = PW_EAP_SUCCESS;
        /*
         * return the MSK (in halves)
         */
        outvps = &handler->request->reply->vps;
        add_reply(outvps, "MS-MPPE-Recv-Key", msk, MPPE_KEY_LEN);
        add_reply(outvps, "MS-MPPE-Send-Key", msk+MPPE_KEY_LEN, MPPE_KEY_LEN);
        ret = 1;
        break;
    default:
        RDEBUG2("unknown PWD state");
        return 0;
    }

    /*
     * we processed the buffered fragments, get rid of them
     */
    if (pwd_session->in_buf) {
        free(pwd_session->in_buf);
        pwd_session->in_buf = NULL;
    }

    return ret;
}
static int attr_rewrite_instantiate(CONF_SECTION *conf, void **instance)
{
	rlm_attr_rewrite_t *data;
	DICT_ATTR *dattr;

	/*
	 *	Set up a storage area for instance data
	 */
	data = rad_malloc(sizeof(*data));
	if (!data) {
		return -1;
	}
	memset(data, 0, sizeof(*data));

	/*
	 *	If the configuration parameters can't be parsed, then
	 *	fail.
	 */
	if (cf_section_parse(conf, data, module_config) < 0) {
		free(data);
		return -1;
	}

	/*
	 *	Discover the attribute number of the key.
	 */
	if (data->attribute == NULL) {
		radlog(L_ERR, "rlm_attr_rewrite: 'attribute' must be set.");
		return -1;
	}
	if (data->search == NULL || data->replace == NULL) {
		radlog(L_ERR, "rlm_attr_rewrite: search/replace strings must be set.");
		return -1;
	}
	data->search_len = strlen(data->search);
	data->replace_len = strlen(data->replace);

	if (data->replace_len == 0 && data->new_attr){
		radlog(L_ERR, "rlm_attr_rewrite: replace string must not be zero length in order to create new attribute.");
		return -1;
	}

	if (data->num_matches < 1 || data->num_matches > MAX_STRING_LEN) {
		radlog(L_ERR, "rlm_attr_rewrite: Illegal range for match number.");
		return -1;
	}
	if (data->searchin_str == NULL) {
		radlog(L_ERR, "rlm_attr_rewrite: Illegal searchin directive given. Assuming packet.");
		data->searchin = RLM_REGEX_INPACKET;
	}
	else{
		if (strcmp(data->searchin_str, "packet") == 0)
			data->searchin = RLM_REGEX_INPACKET;
		else if (strcmp(data->searchin_str, "config") == 0)
			data->searchin = RLM_REGEX_INCONFIG;
		else if (strcmp(data->searchin_str, "control") == 0)
			data->searchin = RLM_REGEX_INCONFIG;
		else if (strcmp(data->searchin_str, "reply") == 0)
			data->searchin = RLM_REGEX_INREPLY;
		else if (strcmp(data->searchin_str, "proxy") == 0)
			data->searchin = RLM_REGEX_INPROXY;
		else if (strcmp(data->searchin_str, "proxy_reply") == 0)
			data->searchin = RLM_REGEX_INPROXYREPLY;
		else {
			radlog(L_ERR, "rlm_attr_rewrite: Illegal searchin directive given. Assuming packet.");
			data->searchin = RLM_REGEX_INPACKET;
		}
	}
	dattr = dict_attrbyname(data->attribute);
	if (dattr == NULL) {
		radlog(L_ERR, "rlm_attr_rewrite: No such attribute %s",
				data->attribute);
		return -1;
	}
	data->attr_num = dattr->attr;
	/* Add the module instance name */
	data->name = cf_section_name2(conf); /* may be NULL */

	*instance = data;

	return 0;
}
Пример #7
0
/*
 * if we have something to log, then we log it
 * otherwise we return the retcode as soon as possible
 */
static int do_logging(char *str, int retcode)
{
	if (str && (*str != '\0'))
		radlog(L_INFO,"%s", str);
	return retcode;
}
Пример #8
0
static int do_linelog(void *instance, REQUEST *request)
{
	int fd = -1;
	char buffer[4096];
	char *p;
	char line[1024];
	rlm_linelog_t *inst = (rlm_linelog_t*) instance;
	const char *value = inst->line;

	if (inst->reference) {
		CONF_ITEM *ci;
		CONF_PAIR *cp;

		radius_xlat(line + 1, sizeof(line) - 2, inst->reference,
			    request, linelog_escape_func);
		line[0] = '.';	/* force to be in current section */

		/*
		 *	Don't allow it to go back up
		 */
		if (line[1] == '.') goto do_log;

		ci = cf_reference_item(NULL, inst->cs, line);
		if (!ci) {
			RDEBUG2("No such entry \"%s\"", line);
			return RLM_MODULE_NOOP;
		}

		if (!cf_item_is_pair(ci)) {
			RDEBUG2("Entry \"%s\" is not a variable assignment ", line);
			goto do_log;
		}

		cp = cf_itemtopair(ci);
		value = cf_pair_value(cp);
		if (!value) {
			RDEBUG2("Entry \"%s\" has no value", line);
			goto do_log;
		}

		/*
		 *	Value exists, but is empty.  Don't log anything.
		 */
		if (!*value) return RLM_MODULE_OK;
	}

 do_log:
	/*
	 *	FIXME: Check length.
	 */
	if (strcmp(inst->filename, "syslog") != 0) {
		radius_xlat(buffer, sizeof(buffer), inst->filename, request,
			    NULL);
		
		/* check path and eventually create subdirs */
		p = strrchr(buffer,'/');
		if (p) {
			*p = '\0';
			if (rad_mkdir(buffer, 0700) < 0) {
				radlog_request(L_ERR, 0, request, "rlm_linelog: Failed to create directory %s: %s", buffer, strerror(errno));
				return RLM_MODULE_FAIL;
			}
			*p = '/';
		}

		fd = open(buffer, O_WRONLY | O_APPEND | O_CREAT, inst->permissions);
		if (fd == -1) {
			radlog(L_ERR, "rlm_linelog: Failed to open %s: %s",
			       buffer, strerror(errno));
			return RLM_MODULE_FAIL;
		}
	}

	/*
	 *	FIXME: Check length.
	 */
	radius_xlat(line, sizeof(line) - 1, value, request,
		    linelog_escape_func);

	if (fd >= 0) {
		strcat(line, "\n");
		
		write(fd, line, strlen(line));
		close(fd);

#ifdef HAVE_SYSLOG_H
	} else {
		syslog(LOG_INFO, "%s", line);
#endif
	}

	return RLM_MODULE_OK;
}
Пример #9
0
/*
 *	Read the users, huntgroups or hints file.
 *	Return a PAIR_LIST.
 */
int pairlist_read(const char *file, PAIR_LIST **list, int complain)
{
	FILE *fp;
	int mode = FIND_MODE_NAME;
	char entry[256];
	char buffer[8192];
	const char *ptr;
	VALUE_PAIR *check_tmp;
	VALUE_PAIR *reply_tmp;
	PAIR_LIST *pl = NULL, *t;
	PAIR_LIST **last = &pl;
	int lineno = 0;
	int old_lineno = 0;
	FR_TOKEN parsecode;
	char newfile[8192];

	/*
	 *	Open the file.  The error message should be a little
	 *	more useful...
	 */
	if ((fp = fopen(file, "r")) == NULL) {
		if (!complain)
			return -1;
		radlog(L_CONS|L_ERR, "Couldn't open %s for reading: %s",
				file, strerror(errno));
		return -1;
	}

	parsecode = T_EOL;

	/*
	 *	Read the entire file into memory for speed.
	 */
	while(fgets(buffer, sizeof(buffer), fp) != NULL) {
		lineno++;
		if (!feof(fp) && (strchr(buffer, '\n') == NULL)) {
			fclose(fp);
			radlog(L_ERR, "%s[%d]: line too long", file, lineno);
			pairlist_free(&pl);
			return -1;
		}
		if (buffer[0] == '#' || buffer[0] == '\n') continue;

		/*
		 *	If the line contains nothing but whitespace,
		 *	ignore it.
		 */
		ptr = buffer;
		while (isspace((int) *ptr)) ptr++;
		if (*ptr == '\0') continue;

parse_again:
		if(mode == FIND_MODE_NAME) {
			/*
			 *	Find the entry starting with the users name
			 */
			if (isspace((int) buffer[0]))  {
				if (parsecode != T_EOL) {
					radlog(L_ERR|L_CONS,
					       "%s[%d]: Unexpected trailing comma for entry %s",
					       file, lineno, entry);
					fclose(fp);
					return -1;
				}
				continue;
			}

			ptr = buffer;
			getword(&ptr, entry, sizeof(entry));

			/*
			 *	Include another file if we see
			 *	$INCLUDE filename
			 */
			if (strcasecmp(entry, "$include") == 0) {
				while(isspace((int) *ptr))
					ptr++;

				/*
				 *	If it's an absolute pathname,
				 *	then use it verbatim.
				 *
				 *	If not, then make the $include
				 *	files *relative* to the current
				 *	file.
				 */
				if (FR_DIR_IS_RELATIVE(ptr)) {
					char *p;

					strlcpy(newfile, file,
						sizeof(newfile));
					p = strrchr(newfile, FR_DIR_SEP);
					if (!p) {
						p = newfile + strlen(newfile);
						*p = FR_DIR_SEP;
					}
					getword(&ptr, p + 1,
						sizeof(newfile) - 1 - (p - buffer));
				} else {
					getword(&ptr, newfile,
						sizeof(newfile));
				}

				t = NULL;
				if (pairlist_read(newfile, &t, 0) != 0) {
					pairlist_free(&pl);
					radlog(L_ERR|L_CONS,
					       "%s[%d]: Could not open included file %s: %s",
					       file, lineno, newfile, strerror(errno));
					fclose(fp);
					return -1;
				}
				*last = t;

				/*
				 *	t may be NULL, it may have one
				 *	entry, or it may be a linked list
				 *	of entries.  Go to the end of the
				 *	list.
				 */
				while (*last)
					last = &((*last)->next);
				continue;
			}

			/*
			 *	Parse the check values
			 */
			check_tmp = NULL;
			reply_tmp = NULL;
			old_lineno = lineno;
			parsecode = userparse(ptr, &check_tmp);
			if (parsecode == T_OP_INVALID) {
				pairlist_free(&pl);
				radlog(L_ERR|L_CONS,
				"%s[%d]: Parse error (check) for entry %s: %s",
					file, lineno, entry, fr_strerror());
				fclose(fp);
				return -1;
			} else if (parsecode == T_COMMA) {
				radlog(L_ERR|L_CONS,
				       "%s[%d]: Unexpected trailing comma in check item list for entry %s",
				       file, lineno, entry);
				fclose(fp);
				return -1;
			}
			mode = FIND_MODE_REPLY;
			parsecode = T_COMMA;
		}
		else {
			if(*buffer == ' ' || *buffer == '\t') {
				if (parsecode != T_COMMA) {
					radlog(L_ERR|L_CONS,
					       "%s[%d]: Syntax error: Previous line is missing a trailing comma for entry %s",
					       file, lineno, entry);
					fclose(fp);
					return -1;
				}

				/*
				 *	Parse the reply values
				 */
				parsecode = userparse(buffer, &reply_tmp);
				/* valid tokens are 1 or greater */
				if (parsecode < 1) {
					pairlist_free(&pl);
					radlog(L_ERR|L_CONS,
					       "%s[%d]: Parse error (reply) for entry %s: %s",
					       file, lineno, entry, fr_strerror());
					fclose(fp);
					return -1;
				}
			}
			else {
				size_t entry_len;
				char *q;

				entry_len = strlen(entry) + 1;

				/*
				 *	Done with this entry...
				 */
				q = rad_malloc(sizeof(*t) + entry_len);
				t = (PAIR_LIST *) q;

				memset(t, 0, sizeof(*t));
				t->check = check_tmp;
				t->reply = reply_tmp;
				t->lineno = old_lineno;
				check_tmp = NULL;
				reply_tmp = NULL;

				q += sizeof(*t);
				memcpy(q, entry, entry_len);
				t->name = q;

				*last = t;
				last = &(t->next);

				mode = FIND_MODE_NAME;
				if (buffer[0] != 0)
					goto parse_again;
			}
		}
	}
	/*
	 *	Make sure that we also read the last line of the file!
	 */
	if (mode == FIND_MODE_REPLY) {
		buffer[0] = 0;
		goto parse_again;
	}
	fclose(fp);

	*list = pl;
	return 0;
}
Пример #10
0
/*************************************************************************
 *
 *	Function: redis_get_socket
 *
 *	Purpose: Return a REDIS socket from the connection pool
 *
 *************************************************************************/
REDISSOCK *redis_get_socket(REDIS_INST *inst)
{
	REDISSOCK *cur, *start;
	int tried_to_connect = 0;
	int unconnected = 0;
	time_t now = time(NULL);

	/*
	 *	Start at the last place we left off.
	 */
	start = inst->last_used;
	if (!start) start = inst->redispool;

	cur = start;

	while (cur) {
#ifdef HAVE_PTHREAD_H
		/*
		 *	If this socket is in use by another thread,
		 *	skip it, and try another socket.
		 *
		 *	If it isn't used, then grab it ourselves.
		 */
		if (pthread_mutex_trylock(&cur->mutex) != 0) {
			goto next;
		} /* else we now have the lock */
#endif

		/*
		 *	If the socket has outlived its lifetime, and
		 *	is connected, close it, and mark it as open for
		 *	reconnections.
		 */
		if (inst->lifetime && (cur->state == sockconnected) &&
		    ((cur->connected + inst->lifetime) < now)) {
			DEBUG2("Closing socket %d as its lifetime has been exceeded", cur->id);
			redis_close_socket(inst, cur);
			cur->state = sockunconnected;
			goto reconnect;
		}

		/*
		 *	If we have performed too many queries over this
		 *	socket, then close it.
		 */
		if (inst->max_queries && (cur->state == sockconnected) &&
		    (cur->queries >= inst->max_queries)) {
			DEBUG2("Closing socket %d as its max_queries has been exceeded", cur->id);
			redis_close_socket(inst, cur);
			cur->state = sockunconnected;
			goto reconnect;
		}

		/*
		 *	If we happen upon an unconnected socket, and
		 *	this instance's grace period on
		 *	(re)connecting has expired, then try to
		 *	connect it.  This should be really rare.
		 */
		if ((cur->state == sockunconnected) && (now > inst->connect_after)) {
		reconnect:
			radlog(L_INFO, "rlm_redis (%s): Trying to (re)connect unconnected handle %d..", inst->xlat_name, cur->id);
			tried_to_connect++;
			connect_single_socket(inst, cur);
		}

		/* if we still aren't connected, ignore this handle */
		if (cur->state == sockunconnected) {
			DEBUG("rlm_redis (%s): Ignoring unconnected handle %d..", inst->xlat_name, cur->id);
			unconnected++;
#ifdef HAVE_PTHREAD_H
			pthread_mutex_unlock(&cur->mutex);
#endif
			goto next;
		}

		/* should be connected, grab it */
		DEBUG("rlm_redis (%s): Reserving redis socket id: %d",
		      inst->xlat_name, cur->id);

		if (unconnected != 0 || tried_to_connect != 0) {
			DEBUG("rlm_redis (%s): got socket %d after skipping %d unconnected handles, tried to reconnect %d though",
			      inst->xlat_name, cur->id, unconnected, tried_to_connect);
		}

		/*
		 *	The socket is returned in the locked
		 *	state.
		 *
		 *	We also remember where we left off,
		 *	so that the next search can start from
		 *	here.
		 *
		 *	Note that multiple threads MAY over-write
		 *	the 'inst->last_used' variable.  This is OK,
		 *	as it's a pointer only used for reading.
		 */
		inst->last_used = cur->next;
		cur->queries++;
		return cur;

		/* move along the list */
	next:
		cur = cur->next;

		/*
		 *	Because we didnt start at the start, once we
		 *	hit the end of the linklist, we should go
		 *	back to the beginning and work toward the
		 *	middle!
		 */
		if (!cur) {
			cur = inst->redispool;
		}

		/*
		 *	If we're at the socket we started
		 */
		if (cur == start) {
			break;
		}
	}

	/*
	 *	Suppress most of the log messages.  We don't want to
	 *	flood the log with this message for EVERY packet.
	 *	Instead, write to the log only once a second or so.
	 *
	 *	This code has race conditions when threaded, but the
	 *	only result is that a few more messages are logged.
	 */
	if (now <= last_logged_failure) return NULL;
	last_logged_failure = now;

	/* We get here if every DB handle is unconnected and unconnectABLE */
	radlog(L_INFO, "rlm_redis (%s): There are no DB handles to use! skipped %d, tried to connect %d",
	       inst->xlat_name, unconnected, tried_to_connect);
	return NULL;
}
Пример #11
0
/** Compare two pair lists except for the password information.
 *
 * For every element in "check" at least one matching copy must be present
 * in "reply".
 *
 * @param req Current request
 * @param request request valuepairs
 * @param check check/control valuepairs
 * @param[in,out] reply reply value pairs
 *
 * @return 0 on match.
 */
int paircompare(REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check,
		VALUE_PAIR **reply)
{
	VALUE_PAIR *check_item;
	VALUE_PAIR *auth_item;
	
	int result = 0;
	int compare;
	int other;

	for (check_item = check;
	     check_item != NULL;
	     check_item = check_item->next) {
		/*
		 *	If the user is setting a configuration value,
		 *	then don't bother comparing it to any attributes
		 *	sent to us by the user.  It ALWAYS matches.
		 */
		if ((check_item->operator == T_OP_SET) ||
		    (check_item->operator == T_OP_ADD)) {
			continue;
		}

		switch (check_item->attribute) {
			/*
			 *	Attributes we skip during comparison.
			 *	These are "server" check items.
			 */
			case PW_CRYPT_PASSWORD:
			case PW_AUTH_TYPE:
			case PW_AUTZ_TYPE:
			case PW_ACCT_TYPE:
			case PW_SESSION_TYPE:
			case PW_STRIP_USER_NAME:
				continue;
				break;

			/*
			 *	IF the password attribute exists, THEN
			 *	we can do comparisons against it.  If not,
			 *	then the request did NOT contain a
			 *	User-Password attribute, so we CANNOT do
			 *	comparisons against it.
			 *
			 *	This hack makes CHAP-Password work..
			 */
			case PW_USER_PASSWORD:
				if (check_item->operator == T_OP_CMP_EQ) {
					DEBUG("WARNING: Found User-Password == \"...\".");
					DEBUG("WARNING: Are you sure you don't mean Cleartext-Password?");
					DEBUG("WARNING: See \"man rlm_pap\" for more information.");
				}
				if (pairfind(request, PW_USER_PASSWORD, 0, TAG_ANY) == NULL) {
					continue;
				}
				break;
		}

		/*
		 *	See if this item is present in the request.
		 */
		other = otherattr(check_item->attribute);

		auth_item = request;
	try_again:
		if (other >= 0) {
			while (auth_item != NULL) {
				if ((auth_item->attribute == 
				    (unsigned int) other) ||
				    (other == 0)) {
					break;
				}
				auth_item = auth_item->next;
			}
		}

		/*
		 *	Not found, it's not a match.
		 */
		if (auth_item == NULL) {
			/*
			 *	Didn't find it.  If we were *trying*
			 *	to not find it, then we succeeded.
			 */
			if (check_item->operator == T_OP_CMP_FALSE) {
				continue;
			} else {
				return -1;
			}
		}

		/*
		 *	Else we found it, but we were trying to not
		 *	find it, so we failed.
		 */
		if (check_item->operator == T_OP_CMP_FALSE) {
			return -1;
		}


		/*
		 *	We've got to xlat the string before doing
		 *	the comparison.
		 */
		if (check_item->flags.do_xlat) {
			int rcode;
			char buffer[sizeof(check_item->vp_strvalue)];

			check_item->flags.do_xlat = 0;
			rcode = radius_xlat(buffer, sizeof(buffer),
					    check_item->vp_strvalue,
					    req, NULL, NULL);

			/*
			 *	Parse the string into a new value.
			 */
			pairparsevalue(check_item, buffer);
		}

		/*
		 *	OK it is present now compare them.
		 */
		compare = radius_callback_compare(req, auth_item, check_item,
						  check, reply);

		switch (check_item->operator) {
			case T_OP_EQ:
			default:
				radlog(L_INFO,  "Invalid operator for item %s: "
						"reverting to '=='", check_item->name);

			case T_OP_CMP_TRUE:
			case T_OP_CMP_FALSE:
			case T_OP_CMP_EQ:
				if (compare != 0) result = -1;
				break;

			case T_OP_NE:
				if (compare == 0) result = -1;
				break;

			case T_OP_LT:
				if (compare >= 0) result = -1;
				break;

			case T_OP_GT:
				if (compare <= 0) result = -1;
				break;

			case T_OP_LE:
				if (compare > 0) result = -1;
				break;

			case T_OP_GE:
				if (compare < 0) result = -1;
				break;

#ifdef HAVE_REGEX_H
			case T_OP_REG_EQ:
			case T_OP_REG_NE:
				if (compare != 0) result = -1;
				break;
#endif
		} /* switch over the operator of the check item */

		/*
		 *	This attribute didn't match, but maybe there's
		 *	another of the same attribute, which DOES match.
		 */
		if ((result != 0) && (other >= 0)) {
			auth_item = auth_item->next;
			result = 0;
			goto try_again;
		}

	} /* for every entry in the check item list */

	return result;
}
Пример #12
0
static int redis_xlat(void *instance, REQUEST *request,
		      char *fmt, char *out, size_t freespace,
		      UNUSED RADIUS_ESCAPE_STRING func)
{
	REDIS_INST *inst = instance;
	REDISSOCK *dissocket;
	size_t ret = 0;
	char *buffer_ptr;
	char buffer[21];
	char querystr[MAX_QUERY_LEN];

	if (!radius_xlat(querystr, sizeof(querystr), fmt, request,
		    redis_escape_func)) {
		radlog(L_ERR, "rlm_redis (%s): xlat failed.",
		       inst->xlat_name);

		return 0;
	}

	if ((dissocket = redis_get_socket(inst)) == NULL) {
		radlog(L_ERR, "rlm_redis (%s): redis_get_socket() failed",
		       inst->xlat_name);
        
		return 0;
	}

	/* Query failed for some reason, release socket and return */
	if (rlm_redis_query(dissocket, inst, querystr) < 0) {
		rlm_redis_finish_query(dissocket);
		redis_release_socket(inst,dissocket);
        
		return 0;
	}

        switch (dissocket->reply->type) {
	case REDIS_REPLY_INTEGER:
                buffer_ptr = buffer;
                snprintf(buffer_ptr, sizeof(buffer), "%lld",
			 dissocket->reply->integer);

                ret = strlen(buffer_ptr);
                break;

	case REDIS_REPLY_STATUS:
	case REDIS_REPLY_STRING:
                buffer_ptr = dissocket->reply->str;
                ret = dissocket->reply->len;
                break;

	default:
                buffer_ptr = NULL;
                break;
        }

	if ((ret >= freespace) || (buffer_ptr == NULL)) {
		RDEBUG("rlm_redis (%s): Can't write result, insufficient space or unsupported result\n",
		       inst->xlat_name);
		
		rlm_redis_finish_query(dissocket);
		redis_release_socket(inst,dissocket);
		
		return 0;
	}
	
	strlcpy(out,buffer_ptr,freespace);
	
	rlm_redis_finish_query(dissocket);
	redis_release_socket(inst,dissocket);
	
	return ret;
}
Пример #13
0
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
	rlm_krb5_t *inst = instance;
	krb5_error_code ret;
#ifndef HEIMDAL_KRB5
	krb5_keytab keytab;
	char keytab_name[200];
	char *princ_name;
#endif

#ifdef HEIMDAL_KRB5
	DEBUG("Using Heimdal Kerberos library");
#else
	DEBUG("Using MIT Kerberos library");
#endif


	if (!krb5_is_thread_safe()) {
/*
 *	rlm_krb5 was built as threadsafe
 */
#ifdef KRB5_IS_THREAD_SAFE
		ERROR("Build time libkrb5 was threadsafe, but run time library claims not to be");
		ERROR("Modify runtime linker path (LD_LIBRARY_PATH on most systems), to prefer threadsafe libkrb5");
		return -1;
/*
 *	rlm_krb5 was not built as threadsafe
 */
#else
		radlog(L_WARN, "libkrb5 is not threadsafe, recompile it with thread support enabled ("
#  ifdef HEIMDAL_KRB5
		       "--enable-pthread-support"
#  else
		       "--disable-thread-support=no"
#  endif
		       ")");
		WARN("rlm_krb5 will run in single threaded mode, performance may be degraded");
	} else {
		WARN("Build time libkrb5 was not threadsafe, but run time library claims to be");
		WARN("Reconfigure and recompile rlm_krb5 to enable thread support");
#endif
	}

	inst->xlat_name = cf_section_name2(conf);
	if (!inst->xlat_name) inst->xlat_name = cf_section_name1(conf);

	ret = krb5_init_context(&inst->context);
	if (ret) {
		ERROR("rlm_krb5 (%s): context initialisation failed: %s", inst->xlat_name,
		      rlm_krb5_error(NULL, ret));

		return -1;
	}

	/*
	 *	Split service principal into service and host components
	 *	they're needed to build the server principal in MIT,
	 *	and to set the validation service in Heimdal.
	 */
	if (inst->service_princ) {
		size_t len;
		/* Service principal appears to contain a host component */
		inst->hostname = strchr(inst->service_princ, '/');
		if (inst->hostname) {
			len = (inst->hostname - inst->service_princ);
			inst->hostname++;
		} else {
			len = strlen(inst->service_princ);
		}

		if (len) {
			inst->service = talloc_array(inst, char, (len + 1));
			strlcpy(inst->service, inst->service_princ, len + 1);
		}
	}
Пример #14
0
/*
 *	Relay the request to a remote server.
 *	Returns:
 *
 *      RLM_MODULE_FAIL: we don't reply, caller returns without replying
 *      RLM_MODULE_NOOP: caller falls through to normal processing
 *      RLM_MODULE_HANDLED  : we reply, caller returns without replying
 */
int proxy_send(REQUEST *request)
{
	int rcode;
	VALUE_PAIR *proxypair;
	VALUE_PAIR *replicatepair;
	VALUE_PAIR *realmpair;
	VALUE_PAIR *namepair;
	VALUE_PAIR *strippednamepair;
	VALUE_PAIR *delaypair;
	VALUE_PAIR *vp, *vps;
	REALM *realm;
	char *realmname;
	int replicating;

	/*
	 *	Not authentication or accounting.  Stop it.
	 */
	if ((request->packet->code != PW_AUTHENTICATION_REQUEST) &&
	    (request->packet->code != PW_ACCOUNTING_REQUEST)) {
		return RLM_MODULE_FAIL;
	}

	/*
	 *	The timestamp is used below to figure the
	 *	next_try. The request needs to "hang around" until
	 *	either the other server sends a reply or the retry
	 *	count has been exceeded.  Until then, it should not
	 *	be eligible for the time-based cleanup.  --Pac. */

	/* Look for proxy/replicate signs */
	/* FIXME - What to do if multiple Proxy-To/Replicate-To attrs are
	 * set...  Log an error? Actually replicate to multiple places? That
	 * would be cool. For now though, I'll just take the first one and
	 * ignore the rest. */
	proxypair = pairfind(request->config_items, PW_PROXY_TO_REALM);
	replicatepair = pairfind(request->config_items, PW_REPLICATE_TO_REALM);
	if (proxypair) {
		realmpair = proxypair;
		replicating = 0;
	} else if (replicatepair) {
		realmpair = replicatepair;
		replicating = 1;
	} else {
		/*
		 *	Neither proxy or replicate attributes are set,
		 *	so we can exit from the proxy code.
		 */
		return RLM_MODULE_NOOP;
	}

	/*
	 *	If the server has already decided to reject the request,
	 *	then don't try to proxy it.
	 */
	if (request->reply->code == PW_AUTHENTICATION_REJECT) {
		DEBUG2("Cancelling proxy as request was already rejected");
		return RLM_MODULE_REJECT;
	}
	if (((vp = pairfind(request->config_items, PW_AUTH_TYPE)) != NULL) &&
	    (vp->lvalue == PW_AUTHTYPE_REJECT)) {
		DEBUG2("Cancelling proxy as request was already rejected");
		return RLM_MODULE_REJECT;
	}
	/*
	 *	Length == 0 means it exists, but there's no realm.
	 *	Don't proxy it.
	 */
	if (realmpair->length == 0) {
		return RLM_MODULE_NOOP;
	}

	realmname = (char *)realmpair->strvalue;

	/*
	 *	Look for the realm, using the load balancing
	 *	version of realm find.
	 */
	realm = proxy_realm_ldb(request, realmname,
				(request->packet->code == PW_ACCOUNTING_REQUEST));
	if (realm == NULL) {
		return RLM_MODULE_FAIL;
	}

	/*
	 *	Remember that we sent the request to a Realm.
	 */
	pairadd(&request->packet->vps,
		pairmake("Realm", realm->realm, T_OP_EQ));
	
	/*
	 *	Access-Request: look for LOCAL realm.
	 *	Accounting-Request: look for LOCAL realm.
	 */
	if (((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
	     (realm->ipaddr == htonl(INADDR_NONE))) ||
	    ((request->packet->code == PW_ACCOUNTING_REQUEST) &&	    
	     (realm->acct_ipaddr == htonl(INADDR_NONE)))) {
		return RLM_MODULE_NOOP;
	}
	
	/*
	 *	Copy the request, then look up
	 *	name and plain-text password in the copy.
	 *
	 *	Note that the User-Name attribute is the *original*
	 *	as sent over by the client.  The Stripped-User-Name
	 *	attribute is the one hacked through the 'hints' file.
	 */
	vps = paircopy(request->packet->vps);
	namepair = pairfind(vps, PW_USER_NAME);
	strippednamepair = pairfind(vps, PW_STRIPPED_USER_NAME);

	/*
	 *	If there's a Stripped-User-Name attribute in the
	 *	request, then use THAT as the User-Name for the
	 *	proxied request, instead of the original name.
	 *
	 *	This is done by making a copy of the Stripped-User-Name
	 *	attribute, turning it into a User-Name attribute,
	 *	deleting the Stripped-User-Name and User-Name attributes
	 *	from the vps list, and making the new User-Name
	 *	the head of the vps list.
	 */
	if (strippednamepair) {
		vp = paircreate(PW_USER_NAME, PW_TYPE_STRING);
		if (!vp) {
			radlog(L_ERR|L_CONS, "no memory");
			exit(1);
		}
		memcpy(vp->strvalue, strippednamepair->strvalue,
				sizeof(vp->strvalue));
		vp->length = strippednamepair->length;
		pairdelete(&vps, PW_USER_NAME);
		pairdelete(&vps, PW_STRIPPED_USER_NAME);
		vp->next = vps;
		namepair = vp;
		vps = vp;
	}

	/*
	 *	Now build a new RADIUS_PACKET and send it.
	 *
	 *	FIXME: it could be that the id wraps around too fast if
	 *	we have a lot of requests, it might be better to keep
	 *	a seperate ID value per remote server.
	 *
	 *	OTOH the remote radius server should be smart enough to
	 *	compare _both_ ID and vector. Right ?
	 */
	if ((request->proxy = rad_alloc(TRUE)) == NULL) {
		radlog(L_ERR|L_CONS, "no memory");
		exit(1);
	}

	/*
	 *	Proxied requests get sent out the proxy FD ONLY.
	 */
	request->proxy->sockfd = proxyfd;

	request->proxy->code = request->packet->code;
	if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
		request->proxy->dst_port = realm->auth_port;
		request->proxy->dst_ipaddr = realm->ipaddr;
	} else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
		request->proxy->dst_port = realm->acct_port;
		request->proxy->dst_ipaddr = realm->acct_ipaddr;
	}
	rad_assert(request->proxy->vps == NULL);
	request->proxy->vps = vps;

	/*
	 *	Add the request to the list of outstanding requests.
	 *	Note that request->proxy->id is a 16 bits value,
	 *	while rad_send sends only the 8 least significant
	 *	bits of that same value.
	 */
	request->proxy->id = (proxy_id++) & 0xff;
	proxy_id &= 0xffff;

	/*
	 *	Add PROXY_STATE attribute.
	 */
	proxy_addinfo(request);

	/*
	 *	If there is no PW_CHAP_CHALLENGE attribute but there
	 *	is a PW_CHAP_PASSWORD we need to add it since we can't
	 *	use the request authenticator anymore - we changed it.
	 */
	if (pairfind(vps, PW_CHAP_PASSWORD) &&
	    pairfind(vps, PW_CHAP_CHALLENGE) == NULL) {
		vp = paircreate(PW_CHAP_CHALLENGE, PW_TYPE_STRING);
		if (!vp) {
			radlog(L_ERR|L_CONS, "no memory");
			exit(1);
		}
		vp->length = AUTH_VECTOR_LEN;
		memcpy(vp->strvalue, request->packet->vector, AUTH_VECTOR_LEN);
		pairadd(&vps, vp);
	}

	/*
	 *	Set up for sending the request.
	 */
	memcpy(request->proxysecret, realm->secret, sizeof(request->proxysecret));
	request->proxy_is_replicate = replicating;
	request->proxy_try_count = mainconfig.proxy_retry_count - 1;
	request->proxy_next_try = request->timestamp + mainconfig.proxy_retry_delay;
	delaypair = pairfind(vps, PW_ACCT_DELAY_TIME);
	request->proxy->timestamp = request->timestamp - (delaypair ? delaypair->lvalue : 0);

	/*
	 *  Do pre-proxying
	 */
	rcode = module_pre_proxy(request);

	/*
	 *	Do NOT free proxy->vps, the pairs are needed for the
	 *	retries! --Pac.
	 */

	/*
	 *	Delay sending the proxy packet until after we've
	 *	done the work above, playing with the request.
	 *
	 *	After this point, it becomes dangerous to play
	 *	with the request data structure, as the reply MAY
	 *	come in and get processed before we're done with it here.
	 *
	 *	Only proxy the packet if the pre-proxy code succeeded.
	 */
	if ((rcode == RLM_MODULE_OK) ||
	    (rcode == RLM_MODULE_NOOP) ||
	    (rcode == RLM_MODULE_UPDATED)) {
		rad_send(request->proxy, NULL, (char *)request->proxysecret);
		if (!replicating) {
			rcode = RLM_MODULE_HANDLED; /* caller doesn't reply */
		} else {
			rcode = RLM_MODULE_NOOP; /* caller replies */
		}
	} else {
		rcode = RLM_MODULE_FAIL; /* caller doesn't reply */
	}

	return rcode;
}
Пример #15
0
static int NEVER_RETURNS
not_implemented(SQLSOCK * sqlsocket, SQL_CONFIG *config)
{
	radlog(L_ERR, "sql_postgresql: calling unimplemented function");
	exit(1);
}
Пример #16
0
/*************************************************************************
 *
 *	Function: sql_fetch_row
 *
 *	Purpose: database specific fetch_row. Returns a SQL_ROW struct
 *               with all the data for the query in 'sqlsocket->row'. Returns
 *		 0 on success, -1 on failure, SQL_DOWN if database is down.
 *
 *************************************************************************/
static int sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config)
{
	int returnCode = -1;
	rlm_sql_sqlite_sock *sqlite_sock = sqlsocket->conn;
	const char *blob;
	int blobLen;
	int status;
	int colindex = 0;
	int colcount = 0;
	int coltype = 0;
	int colintvalue = 0;
	int ret_blob_size = 0;
	char **rowdata = NULL;
	const unsigned char *textStr;
	char intStr[256];
	
	status = sqlite3_step(sqlite_sock->pStmt);
	radlog(L_DBG, "rlm_sql_sqlite: sqlite3_step = %d\n", status);
	if (status == SQLITE_DONE) {
		sql_free_rowdata(sqlsocket, sqlite_sock->columnCount);
		return 0;
	}
	else if (status == SQLITE_ROW) {
		if (sqlite_sock->columnCount == 0) {
			sqlite_sock->columnCount = sql_num_fields(sqlsocket, config);
		}
		colcount = sqlite_sock->columnCount;
		if (colcount == 0)
			return -1;
		
		sql_free_rowdata(sqlsocket, colcount);
		
		ret_blob_size = sizeof(char *) * (colcount+1);
		rowdata = (char **)rad_malloc(ret_blob_size);		/* Space for pointers */
		if (rowdata != NULL) {
			memset(rowdata, 0, ret_blob_size);				/* NULL-pad the pointers */
			sqlsocket->row = rowdata;
		}
		
		for (colindex = 0; colindex < colcount; colindex++)
		{
			coltype = sqlite3_column_type(sqlite_sock->pStmt, colindex);
			switch (coltype)
			{
				case SQLITE_INTEGER:
					colintvalue = sqlite3_column_int(sqlite_sock->pStmt, colindex);
					snprintf(intStr, sizeof(intStr), "%d", colintvalue);
					rowdata[colindex] = strdup(intStr);
					break;
					
				case SQLITE_TEXT:
					textStr = sqlite3_column_text(sqlite_sock->pStmt, colindex);
					if (textStr != NULL)
						rowdata[colindex] = strdup((const char *)textStr);
					break;
					
				case SQLITE_BLOB:
					blob = sqlite3_column_blob(sqlite_sock->pStmt, colindex);
					if (blob != NULL) {
						blobLen = sqlite3_column_bytes(sqlite_sock->pStmt, colindex);
						rowdata[colindex] = (char *)rad_malloc(blobLen + 1);
						if (rowdata[colindex] != NULL) {
							memcpy(rowdata[colindex], blob, blobLen);
						}
					}
					break;
					
				default:
					break;
			}
		}
		
		returnCode = 0;
	}
	
	return returnCode;
}
static int do_attr_rewrite(void *instance, REQUEST *request)
{
	rlm_attr_rewrite_t *data = (rlm_attr_rewrite_t *) instance;
	int ret = RLM_MODULE_NOOP;
	VALUE_PAIR *attr_vp = NULL;
	VALUE_PAIR *tmp = NULL;
	regex_t preg;
	regmatch_t pmatch[9];
	int cflags = 0;
	int err = 0;
	char done_xlat = 0;
	unsigned int len = 0;
	char err_msg[MAX_STRING_LEN];
	unsigned int i = 0;
	unsigned int j = 0;
	unsigned int counter = 0;
	char new_str[MAX_STRING_LEN];
	char *ptr, *ptr2;
	char search_STR[MAX_STRING_LEN];
	char replace_STR[MAX_STRING_LEN];

	if ((attr_vp = pairfind(request->config_items, PW_REWRITE_RULE)) != NULL){
		if (data->name == NULL || strcmp(data->name,attr_vp->vp_strvalue))
			return RLM_MODULE_NOOP;
	}

	if (data->new_attr){
		/* new_attribute = yes */
		if (!radius_xlat(replace_STR, sizeof(replace_STR), data->replace, request, NULL)) {
			DEBUG2("%s: xlat on replace string failed.", data->name);
			return ret;
		}
		attr_vp = pairmake(data->attribute,replace_STR,0);
		if (attr_vp == NULL){
			DEBUG2("%s: Could not add new attribute %s with value '%s'", data->name,
				data->attribute,replace_STR);
			return ret;
		}
		switch(data->searchin){
			case RLM_REGEX_INPACKET:
				pairadd(&request->packet->vps,attr_vp);
				break;
			case RLM_REGEX_INCONFIG:
				pairadd(&request->config_items,attr_vp);
				break;
			case RLM_REGEX_INREPLY:
				pairadd(&request->reply->vps,attr_vp);
				break;
			case RLM_REGEX_INPROXY:
				if (!request->proxy) {
					pairbasicfree(attr_vp);
					return RLM_MODULE_NOOP;
				}
				pairadd(&request->proxy->vps, attr_vp);
				break;
			case RLM_REGEX_INPROXYREPLY:
				if (!request->proxy_reply) {
					pairbasicfree(attr_vp);
					return RLM_MODULE_NOOP;
				}
				pairadd(&request->proxy_reply->vps, attr_vp);
				break;
			default:
				radlog(L_ERR, "%s: Illegal value for searchin. Changing to packet.", data->name);
				data->searchin = RLM_REGEX_INPACKET;
				pairadd(&request->packet->vps,attr_vp);
				break;
		}
		DEBUG2("%s: Added attribute %s with value '%s'", data->name,data->attribute,replace_STR);
		ret = RLM_MODULE_OK;
	} else {
		int replace_len = 0;

		/* new_attribute = no */
		switch (data->searchin) {
			case RLM_REGEX_INPACKET:
				if (data->attr_num == PW_USER_NAME)
					attr_vp = request->username;
				else if (data->attr_num == PW_USER_PASSWORD)
					attr_vp = request->password;
				else
					tmp = request->packet->vps;
				break;
			case RLM_REGEX_INCONFIG:
				tmp = request->config_items;
				break;
			case RLM_REGEX_INREPLY:
				tmp = request->reply->vps;
				break;
			case RLM_REGEX_INPROXYREPLY:
				if (!request->proxy_reply)
					return RLM_MODULE_NOOP;
				tmp = request->proxy_reply->vps;
				break;
			case RLM_REGEX_INPROXY:
				if (!request->proxy)
					return RLM_MODULE_NOOP;
				tmp = request->proxy->vps;
				break;
			default:
				radlog(L_ERR, "%s: Illegal value for searchin. Changing to packet.", data->name);
				data->searchin = RLM_REGEX_INPACKET;
				attr_vp = pairfind(request->packet->vps, data->attr_num);
				break;
		}
do_again:
		if (tmp != NULL)
			attr_vp = pairfind(tmp, data->attr_num);
		if (attr_vp == NULL) {
			DEBUG2("%s: Could not find value pair for attribute %s", data->name,data->attribute);
			return ret;
		}
		if (attr_vp->vp_strvalue == NULL || attr_vp->length == 0){
			DEBUG2("%s: Attribute %s string value NULL or of zero length", data->name,data->attribute);
			return ret;
		}
		cflags |= REG_EXTENDED;
		if (data->nocase)
			cflags |= REG_ICASE;

		if (!radius_xlat(search_STR, sizeof(search_STR), data->search, request, NULL) && data->search_len != 0) {
			DEBUG2("%s: xlat on search string failed.", data->name);
			return ret;
		}

		if ((err = regcomp(&preg,search_STR,cflags))) {
			regerror(err, &preg, err_msg, MAX_STRING_LEN);
			DEBUG2("%s: regcomp() returned error: %s", data->name,err_msg);
			return ret;
		}

		if ((attr_vp->type == PW_TYPE_IPADDR) &&
		    (attr_vp->vp_strvalue[0] == '\0')) {
			inet_ntop(AF_INET, &(attr_vp->vp_ipaddr),
				  attr_vp->vp_strvalue,
				  sizeof(attr_vp->vp_strvalue));
		}

		ptr = new_str;
		ptr2 = attr_vp->vp_strvalue;
		counter = 0;

		for ( i = 0 ;i < (unsigned)data->num_matches; i++) {
			err = regexec(&preg, ptr2, REQUEST_MAX_REGEX, pmatch, 0);
			if (err == REG_NOMATCH) {
				if (i == 0) {
					DEBUG2("%s: Does not match: %s = %s", data->name,
							data->attribute, attr_vp->vp_strvalue);
					regfree(&preg);
					goto to_do_again;
				} else
					break;
			}
			if (err != 0) {
				regfree(&preg);
				radlog(L_ERR, "%s: match failure for attribute %s with value '%s'", data->name,
						data->attribute, attr_vp->vp_strvalue);
				return ret;
			}
			if (pmatch[0].rm_so == -1)
				break;
			len = pmatch[0].rm_so;
			if (data->append) {
				len = len + (pmatch[0].rm_eo - pmatch[0].rm_so);
			}
			counter += len;
			if (counter >= MAX_STRING_LEN) {
				regfree(&preg);
				DEBUG2("%s: Replacement out of limits for attribute %s with value '%s'", data->name,
						data->attribute, attr_vp->vp_strvalue);
				return ret;
			}

			memcpy(ptr, ptr2,len);
			ptr += len;
			*ptr = '\0';
			ptr2 += pmatch[0].rm_eo;

			if (i == 0){
				/*
				 * We only run on the first match, sorry
				 */
				for(j = 0; j <= REQUEST_MAX_REGEX; j++){
					char *p;
					char buffer[sizeof(attr_vp->vp_strvalue)];

					/*
				   	 * Stolen from src/main/valuepair.c, paircompare()
				 	 */

					/*
					 * Delete old matches if the corresponding match does not
					 * exist in the current regex
					 */
					if (pmatch[j].rm_so == -1){
						p = request_data_get(request,request,REQUEST_DATA_REGEX | j);
						if (p){
							free(p);
							continue;
						}
						break;
					}
					memcpy(buffer,
					       attr_vp->vp_strvalue + pmatch[j].rm_so,
					       pmatch[j].rm_eo - pmatch[j].rm_so);
					buffer[pmatch[j].rm_eo - pmatch[j].rm_so] = '\0';
					p = strdup(buffer);
					request_data_add(request,request,REQUEST_DATA_REGEX | j,p,free);
				}
			}

			if (!done_xlat){
				if (data->replace_len != 0 &&
				radius_xlat(replace_STR, sizeof(replace_STR), data->replace, request, NULL) == 0) {
					DEBUG2("%s: xlat on replace string failed.", data->name);
					return ret;
				}
				replace_len = (data->replace_len != 0) ? strlen(replace_STR) : 0;
				done_xlat = 1;
			}

			counter += replace_len;
			if (counter >= MAX_STRING_LEN) {
				regfree(&preg);
				DEBUG2("%s: Replacement out of limits for attribute %s with value '%s'", data->name,
						data->attribute, attr_vp->vp_strvalue);
				return ret;
			}
			if (replace_len){
				memcpy(ptr, replace_STR, replace_len);
				ptr += replace_len;
				*ptr = '\0';
			}
		}
		regfree(&preg);
		len = strlen(ptr2) + 1;		/* We add the ending NULL */
		counter += len;
		if (counter >= MAX_STRING_LEN){
			DEBUG2("%s: Replacement out of limits for attribute %s with value '%s'", data->name,
					data->attribute, attr_vp->vp_strvalue);
			return ret;
		}
		memcpy(ptr, ptr2, len);
		ptr[len] = '\0';

		DEBUG2("%s: Changed value for attribute %s from '%s' to '%s'", data->name,
				data->attribute, attr_vp->vp_strvalue, new_str);
		if (pairparsevalue(attr_vp, new_str) == NULL) {
			DEBUG2("%s: Could not write value '%s' into attribute %s: %s", data->name, new_str, data->attribute, fr_strerror());
			return ret;
		}

to_do_again:
		ret = RLM_MODULE_OK;

		if (tmp != NULL){
			tmp = attr_vp->next;
			if (tmp != NULL)
				goto do_again;
		}
	}

	return ret;
}
Пример #18
0
/*************************************************************************
 *
 *	Function: sql_userparse
 *
 *	Purpose: Read entries from the database and fill VALUE_PAIR structures
 *
 *************************************************************************/
int sql_userparse(VALUE_PAIR ** first_pair, SQL_ROW row)
{
	VALUE_PAIR *pair;
	const char *ptr, *value;
	char buf[MAX_STRING_LEN];
	char do_xlat = 0;
	FR_TOKEN token, operator = T_EOL;

	/*
	 *	Verify the 'Attribute' field
	 */
	if (row[2] == NULL || row[2][0] == '\0') {
		radlog(L_ERR, "rlm_sql: The 'Attribute' field is empty or NULL, skipping the entire row.");
		return -1;
	}

	/*
	 *	Verify the 'op' field
	 */
	if (row[4] != NULL && row[4][0] != '\0') {
		ptr = row[4];
		operator = gettoken(&ptr, buf, sizeof(buf));
		if ((operator < T_OP_ADD) ||
		    (operator > T_OP_CMP_EQ)) {
			radlog(L_ERR, "rlm_sql: Invalid operator \"%s\" for attribute %s", row[4], row[2]);
			return -1;
		}

	} else {
		/*
		 *  Complain about empty or invalid 'op' field
		 */
		operator = T_OP_CMP_EQ;
		radlog(L_ERR, "rlm_sql: The 'op' field for attribute '%s = %s' is NULL, or non-existent.", row[2], row[3]);
		radlog(L_ERR, "rlm_sql: You MUST FIX THIS if you want the configuration to behave as you expect.");
	}

	/*
	 *	The 'Value' field may be empty or NULL
	 */
	value = row[3];
	/*
	 *	If we have a new-style quoted string, where the
	 *	*entire* string is quoted, do xlat's.
	 */
	if (row[3] != NULL &&
	   ((row[3][0] == '\'') || (row[3][0] == '`') || (row[3][0] == '"')) &&
	   (row[3][0] == row[3][strlen(row[3])-1])) {

		token = gettoken(&value, buf, sizeof(buf));
		switch (token) {
			/*
			 *	Take the unquoted string.
			 */
		case T_SINGLE_QUOTED_STRING:
		case T_DOUBLE_QUOTED_STRING:
			value = buf;
			break;

			/*
			 *	Mark the pair to be allocated later.
			 */
		case T_BACK_QUOTED_STRING:
			value = NULL;
			do_xlat = 1;
			break;

			/*
			 *	Keep the original string.
			 */
		default:
			value = row[3];
			break;
		}
	}

	/*
	 *	Create the pair
	 */
	if (do_xlat) {
		pair = pairmake_xlat(row[2], value, operator);
	} else {
		pair = pairmake(row[2], value, operator);
	}
	if (pair == NULL) {
		radlog(L_ERR, "rlm_sql: Failed to create the pair: %s", fr_strerror());
		return -1;
	}

	/*
	 *	Add the pair into the packet
	 */
	pairadd(first_pair, pair);
	return 0;
}
Пример #19
0
/*
 *	Do any per-module initialization that is separate to each
 *	configured instance of the module.  e.g. set up connections
 *	to external databases, read configuration files, set up
 *	dictionary entries, etc.
 *
 *	If configuration information is given in the config section
 *	that must be referenced in later calls, store a handle to it
 *	in *instance otherwise put a null pointer there.
 */
static int sqlippool_instantiate(CONF_SECTION * conf, void ** instance)
{
	module_instance_t *modinst;
	rlm_sqlippool_t * data;
	const char * pool_name = NULL;

	/*
	 *	Set up a storage area for instance data
	 */
	data = rad_malloc(sizeof(*data));
	memset(data, 0, sizeof(*data));

	/*
	 *	If the configuration parameters can't be parsed, then
	 *	fail.
	 */
	if (cf_section_parse(conf, data, module_config) < 0) {
		free(data);
		return -1;
	}

	if (IS_EMPTY(data->sql_instance_name)) {
		radlog(L_ERR, "rlm_sqlippool: the 'sql-instance-name' variable must be set.");
		sqlippool_detach(data);
		return -1;
	}

	/*
	 *	Check that all the queries are in place
	 */

	if (IS_EMPTY(data->allocate_clear)) {
		radlog(L_ERR, "rlm_sqlippool: the 'allocate-clear' statement must be set.");
		sqlippool_detach(data);
		return -1;
	}

	if (IS_EMPTY(data->allocate_find)) {
		radlog(L_ERR, "rlm_sqlippool: the 'allocate-find' statement must be set.");
		sqlippool_detach(data);
		return -1;
	}

	if (IS_EMPTY(data->allocate_update)) {
		radlog(L_ERR, "rlm_sqlippool: the 'allocate-update' statement must be set.");
		sqlippool_detach(data);
		return -1;
	}

	if (IS_EMPTY(data->start_update)) {
		radlog(L_ERR, "rlm_sqlippool: the 'start-update' statement must be set.");
		sqlippool_detach(data);
		return -1;
	}

	if (IS_EMPTY(data->alive_update)) {
		radlog(L_ERR, "rlm_sqlippool: the 'alive-update' statement must be set.");
		sqlippool_detach(data);
		return -1;
	}

	if (IS_EMPTY(data->stop_clear)) {
		radlog(L_ERR, "rlm_sqlippool: the 'stop-clear' statement must be set.");
		sqlippool_detach(data);
		return -1;
	}

	if (IS_EMPTY(data->on_clear)) {
		radlog(L_ERR, "rlm_sqlippool: the 'on-clear' statement must be set.");
		sqlippool_detach(data);
		return -1;
	}

	if (IS_EMPTY(data->off_clear)) {
		radlog(L_ERR, "rlm_sqlippool: the 'off-clear' statement must be set.");
		sqlippool_detach(data);
		return -1;
	}

	pool_name = cf_section_name2(conf);
	if (pool_name != NULL)
		data->pool_name = strdup(pool_name);
	else
		data->pool_name = strdup("ippool");

	modinst = find_module_instance(cf_section_find("modules"),
				       data->sql_instance_name, 1);
	if (!modinst) {
		radlog(L_ERR, "sqlippool_instantiate: failed to find sql instance named %s", data->sql_instance_name);
		sqlippool_detach(data);
		return -1;
	}

	if (strcmp(modinst->entry->name, "rlm_sql") != 0) {
		radlog(L_ERR, "sqlippool_instantiate: Module \"%s\""
		       " is not an instance of the rlm_sql module",
		       data->sql_instance_name);
		sqlippool_detach(data);
		return -1;
	}

	data->sql_inst = (SQL_INST *) modinst->insthandle;

	*instance = data;
	return 0;
}
Пример #20
0
/*
 * Detach a instance give a chance to a module to make some internal setup ...
 */
static int perl_detach(void *instance)
{
	PERL_INST	*inst = (PERL_INST *) instance;
	int 		exitstatus=0,count=0;

#ifdef USE_ITHREADS
	POOL_HANDLE	*handle, *tmp, *tmp2;

	MUTEX_LOCK(&inst->perl_pool->mutex);
	inst->perl_pool->detach = yes;
	MUTEX_UNLOCK(&inst->perl_pool->mutex);

	for (handle = inst->perl_pool->head; handle != NULL; handle = handle->next) {

		radlog(L_DBG,"Detach perl 0x%lx", (unsigned long) handle->clone);
		/*
		 * Wait until clone becomes idle
		 */
		MUTEX_LOCK(&handle->lock);

		/*
		 * Give a clones chance to run detach function
		 */
		{
		dTHXa(handle->clone);
		PERL_SET_CONTEXT(handle->clone);
		{
		dSP; ENTER; SAVETMPS; PUSHMARK(SP);
		count = call_pv(inst->func_detach, G_SCALAR | G_EVAL );
		SPAGAIN;

		if (count == 1) {
			exitstatus = POPi;
			/*
			 * FIXME: bug in perl
			 *
			 */
			if (exitstatus >= 100 || exitstatus < 0) {
				exitstatus = RLM_MODULE_FAIL;
			}
		}
		PUTBACK;
		FREETMPS;
		LEAVE;
		radlog(L_DBG,"detach at 0x%lx returned status %d",
				(unsigned long) handle->clone, exitstatus);
		}
		}
		MUTEX_UNLOCK(&handle->lock);
	}
	/*
	 * Free handles
	 */

	for (tmp = inst->perl_pool->head; tmp !=NULL  ; tmp = tmp2) {
		tmp2 = tmp->next;
		radlog(L_DBG,"rlm_perl:: Destroy perl");
		rlm_perl_destruct(tmp->clone);
		delete_pool_handle(tmp,inst);
	}

	{
	dTHXa(inst->perl);
#endif /* USE_ITHREADS */
	PERL_SET_CONTEXT(inst->perl);
	{
	dSP; ENTER; SAVETMPS;
	PUSHMARK(SP);

	count = call_pv(inst->func_detach, G_SCALAR | G_EVAL );
	SPAGAIN;

	if (count == 1) {
		exitstatus = POPi;
		if (exitstatus >= 100 || exitstatus < 0) {
			exitstatus = RLM_MODULE_FAIL;
		}
	}
	PUTBACK;
	FREETMPS;
	LEAVE;
	}
#ifdef USE_ITHREADS
	}
#endif

	xlat_unregister(inst->xlat_name, perl_xlat);
	free(inst->xlat_name);

	if (inst->func_authorize) free(inst->func_authorize);
	if (inst->func_authenticate) free(inst->func_authenticate);
	if (inst->func_accounting) free(inst->func_accounting);
	if (inst->func_preacct) free(inst->func_preacct);
	if (inst->func_checksimul) free(inst->func_checksimul);
	if (inst->func_pre_proxy) free(inst->func_pre_proxy);
	if (inst->func_post_proxy) free(inst->func_post_proxy);
	if (inst->func_post_auth) free(inst->func_post_auth);
	if (inst->func_detach) free(inst->func_detach);

#ifdef USE_ITHREADS
	free(inst->perl_pool->head);
	free(inst->perl_pool->tail);
	MUTEX_DESTROY(&inst->perl_pool->mutex);
	free(inst->perl_pool);
	rlm_perl_destruct(inst->perl);
#else
	perl_destruct(inst->perl);
	perl_free(inst->perl);
#endif

	free(inst);
	return exitstatus;
}
Пример #21
0
int od_mschap_auth(REQUEST *request, VALUE_PAIR *challenge,
		   VALUE_PAIR * usernamepair)
{
	tDirStatus		status		 = eDSNoErr;
	tDirReference		dsRef		 = 0;
	tDirNodeReference	userNodeRef	 = 0;
	tDataBuffer		*tDataBuff	 = NULL;
	tDataBuffer		*pStepBuff	 = NULL;
	tDataNode		*pAuthType	 = NULL;
	uint32_t		uiCurr		 = 0;
	uint32_t		uiLen		 = 0;
	char			*username_string = NULL;
	char			*shortUserName	 = NULL;
	VALUE_PAIR		*response	 = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE, VENDORPEC_MICROSOFT);
#ifndef NDEBUG
	unsigned int t;
#endif
	
	username_string = (char *) malloc(usernamepair->length + 1);
	if (username_string == NULL)
		return RLM_MODULE_FAIL;
	
	strlcpy(username_string, (char *)usernamepair->vp_strvalue,
		usernamepair->length + 1);
	
	status = dsOpenDirService(&dsRef);
	if (status != eDSNoErr) {
		free(username_string);
		radlog(L_ERR,"rlm_mschap: od_mschap_auth(): dsOpenDirService = %d", status);
		return RLM_MODULE_FAIL;
	}
    
	status = getUserNodeRef(username_string, &shortUserName, &userNodeRef, dsRef);
	if(status != RLM_MODULE_OK) {
		if (status != RLM_MODULE_NOOP) {
			RDEBUG2("od_mschap_auth: getUserNodeRef() failed");
		}
		if (username_string != NULL)
			free(username_string);
		if (dsRef != 0)
			dsCloseDirService(dsRef);
		return status;
	}
	
	/* We got a node; fill the stepBuffer 
	   kDSStdAuthMSCHAP2
	   MS-CHAPv2 authentication method. The Open Directory plug-in generates the reply data for the client. 
	   The input buffer format consists of 
	   a four byte length specifying the length of the user name that follows, the user name, 
	   a four byte value specifying the length of the server challenge that follows, the server challenge, 
	   a four byte value specifying the length of the peer challenge that follows, the peer challenge, 
	   a four byte value specifying the length of the client's digest that follows, and the client's digest. 
	   The output buffer consists of a four byte value specifying the length of the return digest for the client's challenge.
	   r = FillAuthBuff(pAuthBuff, 5,
	   strlen(inName), inName,						// Directory Services long or short name
	   strlen(schal), schal,						// server challenge
	   strlen(peerchal), peerchal,					// client challenge
	   strlen(p24), p24,							// P24 NT-Response
	   4, "User");									// must match the username that was used for the hash
		
	   inName		= 	username_string
	   schal		=   challenge->vp_strvalue
	   peerchal	=   response->vp_strvalue + 2 (16 octets)
	   p24			=   response->vp_strvalue + 26 (24 octets)
	*/

	pStepBuff = dsDataBufferAllocate(dsRef, 4096);
	tDataBuff = dsDataBufferAllocate(dsRef, 4096);
	pAuthType = dsDataNodeAllocateString(dsRef, kDSStdAuthMSCHAP2);
	uiCurr = 0;
	
	RDEBUG2("OD username_string = %s, OD shortUserName=%s (length = %lu)\n", username_string, shortUserName, strlen(shortUserName));
	
	/* User name length + username */
	uiLen = (uint32_t)strlen(shortUserName);
	memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen, sizeof(uiLen));
	uiCurr += sizeof(uiLen);
	memcpy(&(tDataBuff->fBufferData[uiCurr]), shortUserName, uiLen);
	uiCurr += uiLen;
#ifndef NDEBUG
	RDEBUG2("	stepbuf server challenge:\t");
	for (t = 0; t < challenge->length; t++) {
		fprintf(stderr, "%02x", challenge->vp_strvalue[t]);
	}
	fprintf(stderr, "\n");
#endif
	
	/* server challenge (ie. my (freeRADIUS) challenge) */
	uiLen = 16;
	memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen, sizeof(uiLen));
	uiCurr += sizeof(uiLen);
	memcpy(&(tDataBuff->fBufferData[uiCurr]), &(challenge->vp_strvalue[0]),
	       uiLen);
	uiCurr += uiLen;
	
#ifndef NDEBUG
	RDEBUG2("	stepbuf peer challenge:\t\t");
	for (t = 2; t < 18; t++) {
		fprintf(stderr, "%02x", response->vp_strvalue[t]);
	}
	fprintf(stderr, "\n");
#endif
	
	/* peer challenge (ie. the client-generated response) */
	uiLen = 16;
	memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen, sizeof(uiLen));
	uiCurr += sizeof(uiLen);
	memcpy(&(tDataBuff->fBufferData[uiCurr]), &(response->vp_strvalue[2]),
	       uiLen);
	uiCurr += uiLen;	
	
#ifndef NDEBUG
	RDEBUG2("	stepbuf p24:\t\t");
	for (t = 26; t < 50; t++) {
		fprintf(stderr, "%02x", response->vp_strvalue[t]);
	}
	fprintf(stderr, "\n");
#endif
	
	/* p24 (ie. second part of client-generated response) */
	uiLen =  24; /* strlen(&(response->vp_strvalue[26])); may contain NULL byte in the middle. */
	memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen, sizeof(uiLen));
	uiCurr += sizeof(uiLen);
	memcpy(&(tDataBuff->fBufferData[uiCurr]), &(response->vp_strvalue[26]),
	       uiLen);
	uiCurr += uiLen;
	
	/* Client generated use name (short name?) */
	uiLen =  (uint32_t)strlen(username_string);
	memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen, sizeof(uiLen));
	uiCurr += sizeof(uiLen);
	memcpy(&(tDataBuff->fBufferData[uiCurr]), username_string, uiLen);
	uiCurr += uiLen;

	tDataBuff->fBufferLength = uiCurr;
	
	status = dsDoDirNodeAuth(userNodeRef, pAuthType, 1, tDataBuff,
				 pStepBuff, NULL);
	if (status == eDSNoErr) {
		if (pStepBuff->fBufferLength > 4) {
			uint32_t len;
			
			memcpy(&len, pStepBuff->fBufferData, sizeof(len));
			if (len == 40) {
				char mschap_reply[42] = { '\0' };
				pStepBuff->fBufferData[len+4] = '\0';
				mschap_reply[0] = 'S';
				mschap_reply[1] = '=';
				memcpy(&(mschap_reply[2]), &(pStepBuff->fBufferData[4]), len);
				mschap_add_reply(request, &request->reply->vps,
						 *response->vp_strvalue,
						 "MS-CHAP2-Success",
						 mschap_reply, len+2);
				RDEBUG2("dsDoDirNodeAuth returns stepbuff: %s (len=%ld)\n", mschap_reply, len);
			}
		}
	}

	/* clean up */
	if (username_string != NULL)
		free(username_string);
	if (shortUserName != NULL)
		free(shortUserName);

	if (tDataBuff != NULL)
		dsDataBufferDeAllocate(dsRef, tDataBuff);
	if (pStepBuff != NULL)
		dsDataBufferDeAllocate(dsRef, pStepBuff);
	if (pAuthType != NULL)
		dsDataNodeDeAllocate(dsRef, pAuthType);
	if (userNodeRef != 0)
		dsCloseDirNode(userNodeRef);
	if (dsRef != 0)
		dsCloseDirService(dsRef);
	
	if (status != eDSNoErr) {
		errno = EACCES;
		radlog(L_ERR, "rlm_mschap: authentication failed %d", status); /* <-- returns -14091 (eDSAuthMethodNotSupported) -14090 */
		return RLM_MODULE_REJECT;
	}
	
	return RLM_MODULE_OK;
}
Пример #22
0
static int pool_release(POOL_HANDLE *handle, PERL_INST *inst) {

	POOL_HANDLE *tmp, *tmp2;
	int spare, i, t;
	time_t	now;
	/*
	 * Lock it
	 */
	MUTEX_LOCK(&inst->perl_pool->mutex);

	/*
	 * If detach is set then just release the mutex
	 */
	if (inst->perl_pool->detach == yes ) {
	handle->status = idle;
		MUTEX_UNLOCK(&handle->lock);
		MUTEX_UNLOCK(&inst->perl_pool->mutex);
		return 0;
	}

	MUTEX_UNLOCK(&handle->lock);
	handle->status = idle;
	inst->perl_pool->active_clones--;

	spare = inst->perl_pool->current_clones - inst->perl_pool->active_clones;

	radlog(L_DBG,"perl_pool total/active/spare [%d/%d/%d]"
			, inst->perl_pool->current_clones, inst->perl_pool->active_clones, spare);

	if (spare < inst->perl_pool->min_spare_clones) {
		t = inst->perl_pool->min_spare_clones - spare;
		for (i=0;i<t; i++) {
			if ((tmp = pool_grow(inst)) == NULL) {
				MUTEX_UNLOCK(&inst->perl_pool->mutex);
				return -1;
			}
		}
		MUTEX_UNLOCK(&inst->perl_pool->mutex);
		return 0;
	}
	now = time(NULL);
	if ((now - inst->perl_pool->time_when_last_added) < inst->perl_pool->cleanup_delay) {
		MUTEX_UNLOCK(&inst->perl_pool->mutex);
		return 0;
	}
	if (spare > inst->perl_pool->max_spare_clones) {
		spare -= inst->perl_pool->max_spare_clones;
		for (tmp = inst->perl_pool->head; (tmp !=NULL ) && (spare > 0) ; tmp = tmp2) {
			tmp2 = tmp->next;

			if(tmp->status == idle) {
				rlm_destroy_perl(tmp->clone);
				delete_pool_handle(tmp,inst);
				spare--;
				break;
			}
		}
	}
	/*
	 * If the clone have reached max_request_per_clone clean it.
	 */
	if (inst->perl_pool->max_request_per_clone > 0 ) {
			if (handle->request_count > inst->perl_pool->max_request_per_clone) {
				rlm_destroy_perl(handle->clone);
				delete_pool_handle(handle,inst);
		}
	}
	/*
	 * Hurry Up :)
	 */
	MUTEX_UNLOCK(&inst->perl_pool->mutex);
	return 0;
}
Пример #23
0
static int
eap_pwd_initiate (void *type_data, EAP_HANDLER *handler)
{
    pwd_session_t *pwd_session;
    eap_pwd_t *inst = (eap_pwd_t *)type_data;
    VALUE_PAIR *vp;
    pwd_id_packet *pack;

    if (!inst || !handler) {
        radlog(L_ERR, "rlm_eap_pwd: initiate, NULL data provided");
        return -1;
    }

    /*
     * make sure the server's been configured properly
     */
    if (inst->conf->server_id == NULL) {
        radlog(L_ERR, "rlm_eap_pwd: server ID is not configured!");
        return -1;
    }
    switch (inst->conf->group) {
    case 19:
    case 20:
    case 21:
    case 25:
    case 26:
        break;
    default:
        radlog(L_ERR, "rlm_eap_pwd: group is not supported!");
        return -1;
    }

    if ((pwd_session = (pwd_session_t *)malloc(sizeof(*pwd_session))) == NULL) {
        radlog(L_ERR, "rlm_eap_pwd: initiate, out of memory (1)");
        return -1;
    }
    /*
     * set things up so they can be free'd reliably
     */
    pwd_session->group_num = inst->conf->group;
    pwd_session->private_value = NULL;
    pwd_session->peer_scalar = NULL;
    pwd_session->my_scalar = NULL;
    pwd_session->k = NULL;
    pwd_session->my_element = NULL;
    pwd_session->peer_element = NULL;
    pwd_session->group = NULL;
    pwd_session->pwe = NULL;
    pwd_session->order = NULL;
    pwd_session->prime = NULL;

    /*
     * figure out the MTU (basically do what eap-tls does)
     */
    pwd_session->mtu = inst->conf->fragment_size;
    vp = pairfind(handler->request->packet->vps, PW_FRAMED_MTU, 0, TAG_ANY);
    if (vp && ((int)(vp->vp_integer - 9) < pwd_session->mtu)) {
        /*
         * 9 = 4 (EAPOL header) + 4 (EAP header) + 1 (EAP type)
         *
         * the fragmentation code deals with the included length
         * so we don't need to subtract that here.
         */
        pwd_session->mtu = vp->vp_integer - 9;
    }

    pwd_session->state = PWD_STATE_ID_REQ;
    pwd_session->in_buf = NULL;
    pwd_session->out_buf_pos = 0;
    handler->opaque = pwd_session;
    handler->free_opaque = free_session;

    /*
     * construct an EAP-pwd-ID/Request
     */
    pwd_session->out_buf_len = sizeof(pwd_id_packet) + strlen(inst->conf->server_id);
    if ((pwd_session->out_buf = malloc(pwd_session->out_buf_len)) == NULL) {
        radlog(L_ERR, "rlm_eap_pwd: initiate, out of memory to send ID request");
        return -1;
    }
    memset(pwd_session->out_buf, 0, pwd_session->out_buf_len);

    pack = (pwd_id_packet *)pwd_session->out_buf;
    pack->group_num = htons(pwd_session->group_num);
    pack->random_function = EAP_PWD_DEF_RAND_FUN;
    pack->prf = EAP_PWD_DEF_PRF;
    pwd_session->token = random();
    memcpy(pack->token, (char *)&pwd_session->token, 4);
    pack->prep = EAP_PWD_PREP_NONE;
    strcpy(pack->identity, inst->conf->server_id);

    handler->stage = AUTHENTICATE;

    return send_pwd_request(pwd_session, handler->eap_ds);
}
Пример #24
0
/*
 * The xlat function
 */
static int perl_xlat(void *instance, REQUEST *request, char *fmt, char * out,
		     size_t freespace, RADIUS_ESCAPE_STRING func)
{

	PERL_INST	*inst= (PERL_INST *) instance;
	PerlInterpreter *perl;
	char		params[1024], *ptr, *tmp;
	int		count, ret=0;
	STRLEN		n_a;

	/*
	 * Do an xlat on the provided string (nice recursive operation).
	*/
	if (!radius_xlat(params, sizeof(params), fmt, request, func)) {
		radlog(L_ERR, "rlm_perl: xlat failed.");
		return 0;
	}
#ifndef USE_ITHREADS
	perl = inst->perl;
#endif
#ifdef USE_ITHREADS
	POOL_HANDLE	*handle;

	if ((handle = pool_pop(instance)) == NULL) {
		return 0;
	}

	perl = handle->clone;

	radlog(L_DBG,"Found a interpetator 0x%lx",(unsigned long) perl);
	{
	dTHXa(perl);
	}
#endif
	PERL_SET_CONTEXT(perl);
	{
	dSP;
	ENTER;SAVETMPS;

	ptr = strtok(params, " ");

	PUSHMARK(SP);

	while (ptr != NULL) {
		XPUSHs(sv_2mortal(newSVpv(ptr,0)));
		ptr = strtok(NULL, " ");
	}

	PUTBACK;

	count = call_pv(inst->func_xlat, G_SCALAR | G_EVAL);

	SPAGAIN;
	if (SvTRUE(ERRSV)) {
		radlog(L_ERR, "rlm_perl: perl_xlat exit %s\n",
		       SvPV(ERRSV,n_a));
		POPs ;
	} else if (count > 0) {
		tmp = POPp;
		ret = strlen(tmp);
		strncpy(out,tmp,ret);

		radlog(L_DBG,"rlm_perl: Len is %d , out is %s freespace is %d",
		       ret, out,freespace);
	}

	PUTBACK ;
	FREETMPS ;
	LEAVE ;

	}
#ifdef USE_ITHREADS
	pool_release(handle, instance);
#endif
	return ret;
}
Пример #25
0
/*
 * given a radius request with an EAP-SIM body, decode it into TLV pairs
 *
 * return value is TRUE if it succeeded, false if there was something
 * wrong and the packet should be discarded.
 *
 */
int unmap_eapsim_basictypes(RADIUS_PACKET *r,
			    uint8_t *attr, unsigned int attrlen)
{
	VALUE_PAIR              *newvp;
	int                     eapsim_attribute;
	unsigned int            eapsim_len;
	int                     es_attribute_count;

	es_attribute_count=0;

	/* big enough to have even a single attribute */
	if(attrlen < 5) {
		radlog(L_ERR, "eap: EAP-Sim attribute too short: %d < 2", attrlen);
		return 0;
	}

	newvp = paircreate(ATTRIBUTE_EAP_SIM_SUBTYPE, 0, PW_TYPE_INTEGER);
	if (!newvp) return 0;
	newvp->vp_integer = attr[0];
	newvp->length = 1;
	pairadd(&(r->vps), newvp);

	attr     += 3;
	attrlen  -= 3;

	/* now, loop processing each attribute that we find */
	while(attrlen > 0)
	{
		if(attrlen < 2) {
			radlog(L_ERR, "eap: EAP-Sim attribute %d too short: %d < 2", es_attribute_count, attrlen);
			return 0;
		}

		eapsim_attribute = attr[0];
		eapsim_len = attr[1] * 4;

		if(eapsim_len > attrlen) {
			radlog(L_ERR, "eap: EAP-Sim attribute %d (no.%d) has length longer than data (%d > %d)"
			       , eapsim_attribute
			       , es_attribute_count, eapsim_len, attrlen);
			return 0;
		}

		if(eapsim_len > MAX_STRING_LEN) {
			eapsim_len = MAX_STRING_LEN;
		}
		if (eapsim_len < 2) {
			radlog(L_ERR, "eap: EAP-Sim attribute %d (no.%d) has length too small",
			       eapsim_attribute, es_attribute_count);
			       return 0;
		}

		newvp = paircreate(eapsim_attribute+ATTRIBUTE_EAP_SIM_BASE, 0, PW_TYPE_OCTETS);
		memcpy(newvp->vp_strvalue, &attr[2], eapsim_len-2);
		newvp->length = eapsim_len-2;
		pairadd(&(r->vps), newvp);
		newvp = NULL;

		/* advance pointers, decrement length */
		attr += eapsim_len;
		attrlen  -= eapsim_len;
		es_attribute_count++;
	}
	return 1;
}
Пример #26
0
/*
 *	Do any per-module initialization that is separate to each
 *	configured instance of the module.  e.g. set up connections
 *	to external databases, read configuration files, set up
 *	dictionary entries, etc.
 *
 *	If configuration information is given in the config section
 *	that must be referenced in later calls, store a handle to it
 *	in *instance otherwise put a null pointer there.
 *
 *	Boyan:
 *	Setup a hashes wich we will use later
 *	parse a module and give him a chance to live
 *
 */
static int perl_instantiate(CONF_SECTION *conf, void **instance)
{
	PERL_INST       *inst = (PERL_INST *) instance;
	HV		*rad_reply_hv;
	HV		*rad_check_hv;
	HV		*rad_request_hv;
	HV		*rad_request_proxy_hv;
	HV		*rad_request_proxy_reply_hv;
	AV		*end_AV;

	char *embed[4], *xlat_name;
	int exitstatus = 0, argc=0;

	/*
	 *	Set up a storage area for instance data
	 */
	inst = rad_malloc(sizeof(PERL_INST));
	memset(inst, 0, sizeof(PERL_INST));

	/*
	 *	If the configuration parameters can't be parsed, then
	 *	fail.
	 */
	if (cf_section_parse(conf, inst, module_config) < 0) {
		free(inst);
		return -1;
	}


	embed[0] = NULL;
	if (inst->perl_flags) {
		embed[1] = inst->perl_flags;
		embed[2] = inst->module;
		embed[3] = "0";
		argc = 4;
	} else {
		embed[1] = inst->module;
		embed[2] = "0";
		argc = 3;
	}

#ifdef USE_ITHREADS
	inst->perl = interp;
	
	if ((inst->perl = perl_alloc()) == NULL) {
		radlog(L_DBG, "rlm_perl: No memory for allocating new perl !");
		return (-1);
	}

	perl_construct(inst->perl);
	PL_perl_destruct_level = 2;

	{
	dTHXa(inst->perl);
	}
	PERL_SET_CONTEXT(inst->perl);
#else
	if ((inst->perl = perl_alloc()) == NULL) {
		radlog(L_ERR, "rlm_perl: No memory for allocating new perl !");
		return -1;
	}

	perl_construct(inst->perl);
#endif

#if PERL_REVISION >= 5 && PERL_VERSION >=8
	PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
#endif

	exitstatus = perl_parse(inst->perl, xs_init, argc, embed, NULL);

	end_AV = PL_endav;
	PL_endav = Nullav;

	if(!exitstatus) {
		exitstatus = perl_run(inst->perl);
	} else {
		radlog(L_ERR,"rlm_perl: perl_parse failed: %s not found or has syntax errors. \n", inst->module);
		return (-1);
	}

	PL_endav = end_AV;

        newXS("radiusd::radlog",XS_radiusd_radlog, "rlm_perl.c");

	rad_reply_hv = newHV();
	rad_check_hv = newHV();
	rad_request_hv = newHV();
	rad_request_proxy_hv = newHV();
	rad_request_proxy_reply_hv = newHV();

	rad_reply_hv = get_hv("RAD_REPLY",1);
        rad_check_hv = get_hv("RAD_CHECK",1);
        rad_request_hv = get_hv("RAD_REQUEST",1);
	rad_request_proxy_hv = get_hv("RAD_REQUEST_PROXY",1);
	rad_request_proxy_reply_hv = get_hv("RAD_REQUEST_PROXY_REPLY",1);

	xlat_name = cf_section_name2(conf);
	if (xlat_name == NULL)
		xlat_name = cf_section_name1(conf);
	if (xlat_name){
		inst->xlat_name = strdup(xlat_name);
		xlat_register(xlat_name, perl_xlat, inst);
	}

#ifdef USE_ITHREADS
	if ((init_pool(conf, inst)) == -1) {
		radlog(L_ERR,"Couldn't init a pool of perl clones. Exiting");
		return -1;
	}

#endif
	*instance = inst;

	return 0;
}
/*
 *	Compose the response.
 */
static int eapmschapv2_compose(EAP_HANDLER *handler, VALUE_PAIR *reply)
{
	uint8_t *ptr;
	int16_t length;
	mschapv2_header_t *hdr;
	EAP_DS *eap_ds = handler->eap_ds;

	eap_ds->request->code = PW_EAP_REQUEST;
	eap_ds->request->type.type = PW_EAP_MSCHAPV2;

	switch (reply->attribute) {
	case PW_MSCHAP_CHALLENGE:
		/*
		 *   0                   1                   2                   3
		 *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
		 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 *  |     Code      |   Identifier  |            Length             |
		 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 *  |     Type      |   OpCode      |  MS-CHAPv2-ID |  MS-Length...
		 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 *  |   MS-Length   |  Value-Size   |  Challenge...
		 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 *  |                             Challenge...
		 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 *  |                             Name...
		 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 */
		length = MSCHAPV2_HEADER_LEN + MSCHAPV2_CHALLENGE_LEN + strlen(handler->identity);
		eap_ds->request->type.data = malloc(length);
		/*
		 *	Allocate room for the EAP-MS-CHAPv2 data.
		 */
		if (eap_ds->request->type.data == NULL) {
			radlog(L_ERR, "rlm_eap_mschapv2: out of memory");
			return 0;
		}
		eap_ds->request->type.length = length;

		ptr = eap_ds->request->type.data;
		hdr = (mschapv2_header_t *) ptr;

		hdr->opcode = PW_EAP_MSCHAPV2_CHALLENGE;
		hdr->mschapv2_id = eap_ds->response->id + 1;
		length = htons(length);
		memcpy(hdr->ms_length, &length, sizeof(uint16_t));
		hdr->value_size = MSCHAPV2_CHALLENGE_LEN;

		ptr += MSCHAPV2_HEADER_LEN;

		/*
		 *	Copy the Challenge, success, or error over.
		 */
		memcpy(ptr, reply->vp_strvalue, reply->length);
		memcpy((ptr + reply->length), handler->identity, strlen(handler->identity));
		break;

	case PW_MSCHAP2_SUCCESS:
		/*
		 *   0                   1                   2                   3
		 *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
		 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 *  |     Code      |   Identifier  |            Length             |
		 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 *  |     Type      |   OpCode      |  MS-CHAPv2-ID |  MS-Length...
		 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 *  |   MS-Length   |                    Message...
		 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 */
		DEBUG2("MSCHAP Success\n");
		length = 46;
		eap_ds->request->type.data = malloc(length);
		/*
		 *	Allocate room for the EAP-MS-CHAPv2 data.
		 */
		if (eap_ds->request->type.data == NULL) {
			radlog(L_ERR, "rlm_eap_mschapv2: out of memory");
			return 0;
		}
		memset(eap_ds->request->type.data, 0, length);
		eap_ds->request->type.length = length;

		eap_ds->request->type.data[0] = PW_EAP_MSCHAPV2_SUCCESS;
		eap_ds->request->type.data[1] = eap_ds->response->id;
		length = htons(length);
		memcpy((eap_ds->request->type.data + 2), &length, sizeof(uint16_t));
		memcpy((eap_ds->request->type.data + 4), reply->vp_strvalue + 1, 42);
		break;

	case PW_MSCHAP_ERROR:
		DEBUG2("MSCHAP Failure\n");
		length = 4 + reply->length - 1;
		eap_ds->request->type.data = malloc(length);

		/*
		 *	Allocate room for the EAP-MS-CHAPv2 data.
		 */
		if (eap_ds->request->type.data == NULL) {
			radlog(L_ERR, "rlm_eap_mschapv2: out of memory");
			return 0;
		}
		memset(eap_ds->request->type.data, 0, length);
		eap_ds->request->type.length = length;

		eap_ds->request->type.data[0] = PW_EAP_MSCHAPV2_FAILURE;
		eap_ds->request->type.data[1] = eap_ds->response->id;
		length = htons(length);
		memcpy((eap_ds->request->type.data + 2), &length, sizeof(uint16_t));
		/*
		 *	Copy the entire failure message.
		 */
		memcpy((eap_ds->request->type.data + 4),
		       reply->vp_strvalue + 1, reply->length - 1);
		break;

	default:
		radlog(L_ERR, "rlm_eap_mschapv2: Internal sanity check failed");
		return 0;
		break;
	}

	return 1;
}
Пример #28
0
/*
 * 	Call the function_name inside the module
 * 	Store all vps in hashes %RAD_CHECK %RAD_REPLY %RAD_REQUEST
 *
 */
static int rlmperl_call(void *instance, REQUEST *request, char *function_name)
{

	PERL_INST	*inst = instance;
	VALUE_PAIR	*vp;
	int		exitstatus=0, count;
	STRLEN		n_a;

	HV		*rad_reply_hv;
	HV		*rad_check_hv;
	HV		*rad_request_hv;
	HV		*rad_request_proxy_hv;
	HV		*rad_request_proxy_reply_hv;

#ifdef USE_ITHREADS
	POOL_HANDLE	*handle;

	if ((handle = pool_pop(instance)) == NULL) {
		return RLM_MODULE_FAIL;
	}

	radlog(L_DBG,"found interpetator at address 0x%lx",(unsigned long) handle->clone);
	{
	dTHXa(handle->clone);
	PERL_SET_CONTEXT(handle->clone);
	}
#else
	PERL_SET_CONTEXT(inst->perl);
	radlog(L_DBG,"Using perl at 0x%lx",(unsigned long) inst->perl);
#endif
	{
	dSP;

	ENTER;
	SAVETMPS;


	/*
	 *	Radius has told us to call this function, but none
	 *	is defined.
	 */
	if (!function_name) {
		return RLM_MODULE_FAIL;
	}

	rad_reply_hv = get_hv("RAD_REPLY",1);
	rad_check_hv = get_hv("RAD_CHECK",1);
	rad_request_hv = get_hv("RAD_REQUEST",1);
	rad_request_proxy_hv = get_hv("RAD_REQUEST_PROXY",1);
	rad_request_proxy_reply_hv = get_hv("RAD_REQUEST_PROXY_REPLY",1);


	perl_store_vps(request->reply->vps, rad_reply_hv);
	perl_store_vps(request->config_items, rad_check_hv);
	perl_store_vps(request->packet->vps, rad_request_hv);
	
	if (request->proxy != NULL) {
		perl_store_vps(request->proxy->vps, rad_request_proxy_hv);
	} else {
		hv_undef(rad_request_proxy_hv);
	}

	if (request->proxy_reply !=NULL) {
		perl_store_vps(request->proxy_reply->vps, rad_request_proxy_reply_hv);
	} else {
		hv_undef(rad_request_proxy_reply_hv);
	}	
	
	vp = NULL;


	PUSHMARK(SP);
	/*
	* This way %RAD_xx can be pushed onto stack as sub parameters.
	* XPUSHs( newRV_noinc((SV *)rad_request_hv) );
	* XPUSHs( newRV_noinc((SV *)rad_reply_hv) );
	* XPUSHs( newRV_noinc((SV *)rad_check_hv) );
	* PUTBACK;
	*/

	count = call_pv(function_name, G_SCALAR | G_EVAL | G_NOARGS);

	SPAGAIN;

	if (SvTRUE(ERRSV)) {
		radlog(L_ERR, "rlm_perl: perl_embed:: module = %s , func = %s exit status= %s\n",
		       inst->module,
		       function_name, SvPV(ERRSV,n_a));
		POPs;
	}

	if (count == 1) {
		exitstatus = POPi;
		if (exitstatus >= 100 || exitstatus < 0) {
			exitstatus = RLM_MODULE_FAIL;
		}
	}
	

	PUTBACK;
	FREETMPS;
	LEAVE;


	if ((get_hv_content(rad_reply_hv, &vp)) > 0 ) {
		pairmove(&request->reply->vps, &vp);
		pairfree(&vp);
	}

	if ((get_hv_content(rad_check_hv, &vp)) > 0 ) {
		pairmove(&request->config_items, &vp);
		pairfree(&vp);
	}
	
	if ((get_hv_content(rad_request_proxy_reply_hv, &vp)) > 0 && request->proxy_reply != NULL) {
		pairfree(&request->proxy_reply->vps);
		pairmove(&request->proxy_reply->vps, &vp);
		pairfree(&vp);
	}
	}
#ifdef USE_ITHREADS
	pool_release(handle,instance);
	radlog(L_DBG,"Unreserve perl at address 0x%lx", (unsigned long) handle->clone);
#endif

	return exitstatus;
}
/*
 *	Do post-proxy processing,
 *	0 = fail
 *	1 = OK.
 *
 *	Called from rlm_eap.c, eap_postproxy().
 */
static int mschap_postproxy(EAP_HANDLER *handler, void *tunnel_data)
{
	VALUE_PAIR *response = NULL;
	mschapv2_opaque_t *data;

	data = (mschapv2_opaque_t *) handler->opaque;
	rad_assert(data != NULL);

	tunnel_data = tunnel_data; /* -Wunused */

	DEBUG2("  rlm_eap_mschapv2: Passing reply from proxy back into the tunnel %p %d.",
	       handler->request, handler->request->reply->code);

	/*
	 *	There is only a limited number of possibilities.
	 */
	switch (handler->request->reply->code) {
	case PW_AUTHENTICATION_ACK:
		DEBUG("  rlm_eap_mschapv2: Proxied authentication succeeded.");
		/*
		 *	Move the attribute, so it doesn't go into
		 *	the reply.
		 */
		pairmove2(&response,
			  &handler->request->reply->vps,
			  PW_MSCHAP2_SUCCESS, VENDORPEC_MICROSOFT, TAG_ANY);
		break;

	default:
	case PW_AUTHENTICATION_REJECT:
		DEBUG("  rlm_eap_mschapv2: Proxied authentication did not succeed.");
		return 0;
	}

	/*
	 *	No response, die.
	 */
	if (!response) {
		radlog(L_ERR, "rlm_eap_mschapv2: Proxied reply contained no MS-CHAPv2-Success or MS-CHAP-Error");
		return 0;
	}

	/*
	 *	Done doing EAP proxy stuff.
	 */
	handler->request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
	eapmschapv2_compose(handler, response);
	data->code = PW_EAP_MSCHAPV2_SUCCESS;

	/*
	 *	Delete MPPE keys & encryption policy
	 *
	 *	FIXME: Use intelligent names...
	 */
	fix_mppe_keys(handler, data);

	/*
	 * save any other attributes for re-use in the final
	 * access-accept e.g. vlan, etc. This lets the PEAP
	 * use_tunneled_reply code work
	 */
	data->reply = paircopy(handler->request->reply->vps);

	/*
	 *	And we need to challenge the user, not ack/reject them,
	 *	so we re-write the ACK to a challenge.  Yuck.
	 */
	handler->request->reply->code = PW_ACCESS_CHALLENGE;
	pairfree(&response);

	return 1;
}
Пример #30
0
/*
 *	Check one terminal server to see if a user is logged in.
 *
 *	Return values:
 *		0 The user is off-line.
 *		1 The user is logged in.
 *		2 Some error occured.
 */
int rad_check_ts(uint32_t nasaddr, unsigned int portnum, const char *user,
		 const char *session_id)
{
	pid_t	pid, child_pid;
	int	status;
	char	address[16];
	char	port[11];
	RADCLIENT *cl;
	fr_ipaddr_t ipaddr;

	ipaddr.af = AF_INET;
	ipaddr.ipaddr.ip4addr.s_addr = nasaddr;

	/*
	 *	Find NAS type.
	 */
	cl = client_find_old(&ipaddr);
	if (!cl) {
		/*
		 *  Unknown NAS, so trusting radutmp.
		 */
		DEBUG2("checkrad: Unknown NAS %s, not checking",
		       ip_ntoa(address, nasaddr));
		return 1;
	}

	/*
	 *  No nastype, or nas type 'other', trust radutmp.
	 */
	if (!cl->nastype || (cl->nastype[0] == '\0') ||
	    (strcmp(cl->nastype, "other") == 0)) {
		DEBUG2("checkrad: No NAS type, or type \"other\" not checking");
		return 1;
	}

	/*
	 *	Fork.
	 */
	if ((pid = rad_fork()) < 0) { /* do wait for the fork'd result */
		radlog(L_ERR, "Accounting: Failed in fork(): Cannot run checkrad\n");
		return 2;
	}

	if (pid > 0) {
		child_pid = rad_waitpid(pid, &status);

		/*
		 *	It's taking too long.  Stop waiting for it.
		 *
		 *	Don't bother to kill it, as we don't care what
		 *	happens to it now.
		 */
		if (child_pid == 0) {
			radlog(L_ERR, "Check-TS: timeout waiting for checkrad");
			return 2;
		}

		if (child_pid < 0) {
			radlog(L_ERR, "Check-TS: unknown error in waitpid()");
			return 2;
		}

		return WEXITSTATUS(status);
	}

	/*
	 *  We don't close fd's 0, 1, and 2.  If we're in debugging mode,
	 *  then they should go to stdout (etc), along with the other
	 *  server log messages.
	 *
	 *  If we're not in debugging mode, then the code in radiusd.c
	 *  takes care of connecting fd's 0, 1, and 2 to /dev/null.
	 */
	closefrom(3);

	ip_ntoa(address, nasaddr);
	snprintf(port, 11, "%u", portnum);

#ifdef __EMX__
	/* OS/2 can't directly execute scripts then we call the command
	   processor to execute checkrad
	*/
	execl(getenv("COMSPEC"), "", "/C","checkrad", cl->nastype, address, port,
		user, session_id, NULL);
#else
	execl(mainconfig.checkrad, "checkrad", cl->nastype, address, port,
		user, session_id, NULL);
#endif
	radlog(L_ERR, "Check-TS: exec %s: %s", mainconfig.checkrad, strerror(errno));

	/*
	 *	Exit - 2 means "some error occured".
	 */
	exit(2);
	return 2;
}