Ejemplo n.º 1
0
static size_t rand_xlat(void *instance, REQUEST *request, char *fmt,
			char *out, size_t outlen,
			RADIUS_ESCAPE_STRING func)
{
	int64_t		result;
	rlm_expr_t	*inst = instance;
	char		buffer[256];

	inst = inst;		/* -Wunused */

	/*
	 * Do an xlat on the provided string (nice recursive operation).
	 */
	if (!radius_xlat(buffer, sizeof(buffer), fmt, request, func)) {
		radlog(L_ERR, "rlm_expr: xlat failed.");
		return 0;
	}

	result = atoi(buffer);

	/*
	 *	Too small or too big.
	 */
	if (result <= 0) return 0;
	if (result >= (1 << 30)) result = (1 << 30);

	result *= fr_rand();	/* 0..2^32-1 */
	result >>= 32;

	snprintf(out, outlen, "%ld", (long int) result);
	return strlen(out);
}
Ejemplo n.º 2
0
/**
 *  @brief Generate a random integer value
 *
 */
static size_t rand_xlat(UNUSED void *instance, REQUEST *request, const char *fmt,
			char *out, size_t outlen)
{
	int64_t		result;
	char		buffer[256];

	/*
	 * Do an xlat on the provided string (nice recursive operation).
	 */
	if (!radius_xlat(buffer, sizeof(buffer), fmt, request, NULL, NULL)) {
		RDEBUGE("xlat failed.");
		*out = '\0';
		return 0;
	}

	result = atoi(buffer);

	/*
	 *	Too small or too big.
	 */
	if (result <= 0) return 0;
	if (result >= (1 << 30)) result = (1 << 30);

	result *= fr_rand();	/* 0..2^32-1 */
	result >>= 32;

	snprintf(out, outlen, "%ld", (long int) result);
	return strlen(out);
}
Ejemplo n.º 3
0
/** Generate some random bytes
 *
 * @param rnd_data Buffer to write bytes to.
 * @param len Number of bytes to write.
 */
void otp_get_random(uint8_t *rnd_data, size_t len)
{
    size_t bytes_read = 0;
    size_t bytes_left;
    int n;

    while (bytes_read < len) {
        bytes_left = len - bytes_read;
        uint32_t r = fr_rand();

        n = sizeof(r) < bytes_left ? sizeof(r) : bytes_left;

        memcpy(rnd_data + bytes_read, &r, n);

        bytes_read += n;
    }
}
Ejemplo n.º 4
0
/**
 *  @brief Generate a random integer value
 *
 */
static size_t rand_xlat(UNUSED void *instance, UNUSED REQUEST *request, char const *fmt,
			char *out, size_t outlen)
{
	int64_t		result;

	result = atoi(fmt);

	/*
	 *	Too small or too big.
	 */
	if (result <= 0) return 0;
	if (result >= (1 << 30)) result = (1 << 30);

	result *= fr_rand();	/* 0..2^32-1 */
	result >>= 32;

	snprintf(out, outlen, "%ld", (long int) result);
	return strlen(out);
}
Ejemplo n.º 5
0
static int mschapv1_encode(RADIUS_PACKET *packet, VALUE_PAIR **request,
			   char const *password)
{
	unsigned int i;
	uint8_t *p;
	VALUE_PAIR *challenge, *reply;
	uint8_t nthash[16];

	fr_pair_delete_by_num(&packet->vps, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT, TAG_ANY);
	fr_pair_delete_by_num(&packet->vps, PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT, TAG_ANY);

	challenge = fr_pair_afrom_num(packet, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT);
	if (!challenge) {
		return 0;
	}

	fr_pair_add(request, challenge);
	challenge->vp_length = 8;
	challenge->vp_octets = p = talloc_array(challenge, uint8_t, challenge->vp_length);
	for (i = 0; i < challenge->vp_length; i++) {
		p[i] = fr_rand();
	}

	reply = fr_pair_afrom_num(packet, PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT);
	if (!reply) {
		return 0;
	}

	fr_pair_add(request, reply);
	reply->vp_length = 50;
	reply->vp_octets = p = talloc_array(reply, uint8_t, reply->vp_length);
	memset(p, 0, reply->vp_length);

	p[1] = 0x01; /* NT hash */

	if (mschap_ntpwdhash(nthash, password) < 0) {
		return 0;
	}

	smbdes_mschap(nthash, challenge->vp_octets, p + 26);
	return 1;
}
Ejemplo n.º 6
0
static int mschapv1_encode(RADIUS_PACKET *packet, VALUE_PAIR **request,
                           char const *password)
{
    unsigned int i;
    uint8_t *p;
    VALUE_PAIR *challenge, *response;
    uint8_t nthash[16];

    challenge = paircreate(packet, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT);
    if (!challenge) {
        fprintf(stderr, "GOT IT %d!\n", __LINE__);
        return 0;
    }

    pairadd(request, challenge);
    challenge->length = 8;
    challenge->vp_octets = p = talloc_array(challenge, uint8_t, challenge->length);
    for (i = 0; i < challenge->length; i++) {
        p[i] = fr_rand();
    }

    response = paircreate(packet, PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT);
    if (!response) {
        fprintf(stderr, "GOT IT %d!\n", __LINE__);
        return 0;
    }

    pairadd(request, response);
    response->length = 50;
    response->vp_octets = p = talloc_array(response, uint8_t, response->length);
    memset(p, 0, response->length);

    p[1] = 0x01; /* NT hash */

    mschap_ntpwdhash(nthash, password);

    smbdes_mschap(nthash, challenge->vp_octets,
                  p + 26);
    return 1;
}
Ejemplo n.º 7
0
static int mschapv1_encode(VALUE_PAIR **request, const char *password)
{
	unsigned int i;
	VALUE_PAIR *challenge, *response;
	uint8_t nthash[16];

	challenge = paircreate(PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT, PW_TYPE_OCTETS);
	if (!challenge) {
		fprintf(stderr, "GOT IT %d!\n", __LINE__);
		return 0;
	}

	pairadd(request, challenge);
	challenge->length = 8;
	for (i = 0; i < challenge->length; i++) {
		challenge->vp_octets[i] = fr_rand();
	}

	response = paircreate(PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT, PW_TYPE_OCTETS);
	if (!response) {
		fprintf(stderr, "GOT IT %d!\n", __LINE__);
		return 0;
	}

	pairadd(request, response);
	response->length = 50;
	memset(response->vp_octets, 0, response->length);

	response->vp_octets[1] = 0x01; /* NT hash */

	mschap_ntpwdhash(nthash, password);

	smbdes_mschap(nthash, challenge->vp_octets,
		      response->vp_octets + 26);
	return 1;
}
Ejemplo n.º 8
0
/*
 * we got an EAP-Request/Sim/Start message in a legal state.
 *
 * pick a supported version, put it into the reply, and insert a nonce.
 */
static int process_eap_start(RADIUS_PACKET *req,
			     RADIUS_PACKET *rep)
{
	VALUE_PAIR *vp, *newvp;
	VALUE_PAIR *anyidreq_vp, *fullauthidreq_vp, *permanentidreq_vp;
	uint16_t const *versions;
	uint16_t selectedversion;
	unsigned int i,versioncount;

	/* form new response clear of any EAP stuff */
	cleanresp(rep);

	if((vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_VERSION_LIST, 0, TAG_ANY)) == NULL) {
		fprintf(stderr, "illegal start message has no VERSION_LIST\n");
		return 0;
	}

	versions = (uint16_t const *) vp->vp_strvalue;

	/* verify that the attribute length is big enough for a length field */
	if(vp->length < 4)
	{
		fprintf(stderr, "start message has illegal VERSION_LIST. Too short: %u\n", (unsigned int) vp->length);
		return 0;
	}

	versioncount = ntohs(versions[0])/2;
	/* verify that the attribute length is big enough for the given number
	 * of versions present.
	 */
	if((unsigned)vp->length <= (versioncount*2 + 2))
	{
		fprintf(stderr, "start message is too short. Claimed %d versions does not fit in %u bytes\n", versioncount, (unsigned int) vp->length);
		return 0;
	}

	/*
	 * record the versionlist for the MK calculation.
	 */
	eapsim_mk.versionlistlen = versioncount*2;
	memcpy(eapsim_mk.versionlist, (unsigned char const *)(versions+1),
	       eapsim_mk.versionlistlen);

	/* walk the version list, and pick the one we support, which
	 * at present, is 1, EAP_SIM_VERSION.
	 */
	selectedversion=0;
	for(i=0; i < versioncount; i++)
	{
		if(ntohs(versions[i+1]) == EAP_SIM_VERSION)
		{
			selectedversion=EAP_SIM_VERSION;
			break;
		}
	}
	if(selectedversion == 0)
	{
		fprintf(stderr, "eap-sim start message. No compatible version found. We need %d\n", EAP_SIM_VERSION);
		for(i=0; i < versioncount; i++)
		{
			fprintf(stderr, "\tfound version %d\n",
				ntohs(versions[i+1]));
		}
	}

	/*
	 * now make sure that we have only FULLAUTH_ID_REQ.
	 * I think that it actually might not matter - we can answer in
	 * anyway we like, but it is illegal to have more than one
	 * present.
	 */
	anyidreq_vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_ANY_ID_REQ, 0, TAG_ANY);
	fullauthidreq_vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_FULLAUTH_ID_REQ, 0, TAG_ANY);
	permanentidreq_vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_PERMANENT_ID_REQ, 0, TAG_ANY);

	if(!fullauthidreq_vp ||
	   anyidreq_vp != NULL ||
	   permanentidreq_vp != NULL) {
		fprintf(stderr, "start message has %sanyidreq, %sfullauthid and %spermanentid. Illegal combination.\n",
			(anyidreq_vp != NULL ? "a " : "no "),
			(fullauthidreq_vp != NULL ? "a " : "no "),
			(permanentidreq_vp != NULL ? "a " : "no "));
		return 0;
	}

	/* okay, we have just any_id_req there, so fill in response */

	/* mark the subtype as being EAP-SIM/Response/Start */
	newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_SUBTYPE, 0);
	newvp->vp_integer = eapsim_start;
	pairreplace(&(rep->vps), newvp);

	/* insert selected version into response. */
	{
		uint16_t no_versions;

		no_versions = htons(selectedversion);

		newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_BASE + PW_EAP_SIM_SELECTED_VERSION, 0);
		pairmemcpy(newvp, (uint8_t *) &no_versions, 2);
		pairreplace(&(rep->vps), newvp);

		/* record the selected version */
		memcpy(eapsim_mk.versionselect, &no_versions, 2);
	}

	vp = newvp = NULL;

	{
		uint32_t nonce[4];
		uint8_t *p;
		/*
		 * insert a nonce_mt that we make up.
		 */
		nonce[0]=fr_rand();
		nonce[1]=fr_rand();
		nonce[2]=fr_rand();
		nonce[3]=fr_rand();

		newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_NONCE_MT, 0);

		p = talloc_zero_array(newvp, uint8_t, 18); /* 18 = 16 bytes of nonce + padding */
		memcpy(&p[2], nonce, 16);
		pairmemsteal(newvp, p);

		pairreplace(&(rep->vps), newvp);

		/* also keep a copy of the nonce! */
		memcpy(eapsim_mk.nonce_mt, nonce, 16);
	}

	{
		uint16_t idlen;
		uint8_t *p;
		uint16_t no_idlen;

		/*
		 * insert the identity here.
		 */
		vp = pairfind(rep->vps, PW_USER_NAME, 0, TAG_ANY);
		if(!vp)
		{
			fprintf(stderr, "eap-sim: We need to have a User-Name attribute!\n");
			return 0;
		}
		newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_IDENTITY, 0);

		idlen = strlen(vp->vp_strvalue);
		p = talloc_zero_array(newvp, uint8_t, idlen + 2);
		no_idlen = htons(idlen);
		memcpy(p, &no_idlen, 2);
		memcpy(p + 2, vp->vp_strvalue, idlen);
		pairmemsteal(newvp, p);

		pairreplace(&(rep->vps), newvp);

		/* record it */
		memcpy(eapsim_mk.identity, vp->vp_strvalue, idlen);
		eapsim_mk.identitylen = idlen;
	}

	return 1;
}
Ejemplo n.º 9
0
/*
 *	Write accounting information to this modules database.
 */
static int replicate_packet(void *instance, REQUEST *request)
{
    int rcode = RLM_MODULE_NOOP;
    VALUE_PAIR *vp, *last;
    home_server *home;
    REALM *realm;
    home_pool_t *pool;
    RADIUS_PACKET *packet = NULL;

    instance = instance;	/* -Wunused */
    last = request->config_items;

    /*
     *	Send as many packets as necessary to different
     *	destinations.
     */
    while (1) {
        vp = pairfind(last, PW_REPLICATE_TO_REALM, 0);
        if (!vp) break;

        last = vp->next;

        realm = realm_find2(vp->vp_strvalue);
        if (!realm) {
            RDEBUG2("ERROR: Cannot Replicate to unknown realm %s", realm);
            continue;
        }

        /*
         *	We shouldn't really do this on every loop.
         */
        switch (request->packet->code) {
        default:
            RDEBUG2("ERROR: Cannot replicate unknown packet code %d",
                    request->packet->code);
            cleanup(packet);
            return RLM_MODULE_FAIL;

        case PW_AUTHENTICATION_REQUEST:
            pool = realm->auth_pool;
            break;

#ifdef WITH_ACCOUNTING

        case PW_ACCOUNTING_REQUEST:
            pool = realm->acct_pool;
            break;
#endif

#ifdef WITH_COA
        case PW_COA_REQUEST:
        case PW_DISCONNECT_REQUEST:
            pool = realm->acct_pool;
            break;
#endif
        }

        if (!pool) {
            RDEBUG2(" WARNING: Cancelling replication to Realm %s, as the realm is local.", realm->name);
            continue;
        }

        home = home_server_ldb(realm->name, pool, request);
        if (!home) {
            RDEBUG2("ERROR: Failed to find live home server for realm %s",
                    realm->name);
            continue;
        }

        if (!packet) {
            packet = rad_alloc(1);
            if (!packet) return RLM_MODULE_FAIL;
            packet->sockfd = -1;
            packet->code = request->packet->code;
            packet->id = fr_rand() & 0xff;

            packet->sockfd = fr_socket(&home->src_ipaddr, 0);
            if (packet->sockfd < 0) {
                RDEBUG("ERROR: Failed opening socket: %s", fr_strerror());
                cleanup(packet);
                return RLM_MODULE_FAIL;
            }

            packet->vps = paircopy(request->packet->vps);
            if (!packet->vps) {
                RDEBUG("ERROR: Out of memory!");
                cleanup(packet);
                return RLM_MODULE_FAIL;
            }

            /*
             *	For CHAP, create the CHAP-Challenge if
             *	it doesn't exist.
             */
            if ((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
                    (pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0) != NULL) &&
                    (pairfind(request->packet->vps, PW_CHAP_CHALLENGE, 0) == NULL)) {
                vp = radius_paircreate(request, &packet->vps,
                                       PW_CHAP_CHALLENGE, 0,
                                       PW_TYPE_OCTETS);
                vp->length = AUTH_VECTOR_LEN;
                memcpy(vp->vp_strvalue, request->packet->vector,
                       AUTH_VECTOR_LEN);
            }
        } else {
            size_t i;

            for (i = 0; i < sizeof(packet->vector); i++) {
                packet->vector[i] = fr_rand() & 0xff;
            }

            packet->id++;
            free(packet->data);
            packet->data = NULL;
            packet->data_len = 0;
        }

        /*
         *	(Re)-Write these.
         */
        packet->dst_ipaddr = home->ipaddr;
        packet->dst_port = home->port;
        memset(&packet->src_ipaddr, 0, sizeof(packet->src_ipaddr));
        packet->src_port = 0;

        /*
         *	Encode, sign and then send the packet.
         */
        RDEBUG("Replicating packet to Realm %s", realm->name);
        if (rad_send(packet, NULL, home->secret) < 0) {
            RDEBUG("ERROR: Failed replicating packet: %s",
                   fr_strerror());
            cleanup(packet);
            return RLM_MODULE_FAIL;
        }

        /*
         *	We've sent it to at least one destination.
         */
        rcode = RLM_MODULE_OK;
    }

    cleanup(packet);
    return rcode;
}
Ejemplo n.º 10
0
static int mod_session_init (void *instance, eap_handler_t *handler)
{
	pwd_session_t *session;
	eap_pwd_t *inst = (eap_pwd_t *)instance;
	VALUE_PAIR *vp;
	pwd_id_packet_t *packet;

	if (!inst || !handler) {
		ERROR("rlm_eap_pwd: Initiate, NULL data provided");
		return 0;
	}

	/*
	* make sure the server's been configured properly
	*/
	if (!inst->server_id) {
		ERROR("rlm_eap_pwd: Server ID is not configured");
		return 0;
	}
	switch (inst->group) {
	case 19:
	case 20:
	case 21:
	case 25:
	case 26:
		break;

	default:
		ERROR("rlm_eap_pwd: Group is not supported");
		return 0;
	}

	if ((session = talloc_zero(handler, pwd_session_t)) == NULL) return 0;
	talloc_set_destructor(session, _free_pwd_session);
	/*
	 * set things up so they can be free'd reliably
	 */
	session->group_num = inst->group;
	session->private_value = NULL;
	session->peer_scalar = NULL;
	session->my_scalar = NULL;
	session->k = NULL;
	session->my_element = NULL;
	session->peer_element = NULL;
	session->group = NULL;
	session->pwe = NULL;
	session->order = NULL;
	session->prime = NULL;

	/*
	 *	The admin can dynamically change the MTU.
	 */
	session->mtu = inst->fragment_size;
	vp = fr_pair_find_by_num(handler->request->packet->vps, PW_FRAMED_MTU, 0, TAG_ANY);

	/*
	 *	session->mtu is *our* MTU.  We need to subtract off the EAP
	 *	overhead.
	 *
	 *	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.
	 */
	if (vp && (vp->vp_integer > 100) && (vp->vp_integer < session->mtu)) {
		session->mtu = vp->vp_integer - 9;
	}

	session->state = PWD_STATE_ID_REQ;
	session->in = NULL;
	session->out_pos = 0;
	handler->opaque = session;

	/*
	 * construct an EAP-pwd-ID/Request
	 */
	session->out_len = sizeof(pwd_id_packet_t) + strlen(inst->server_id);
	if ((session->out = talloc_zero_array(session, uint8_t, session->out_len)) == NULL) {
		return 0;
	}

	packet = (pwd_id_packet_t *)session->out;
	packet->group_num = htons(session->group_num);
	packet->random_function = EAP_PWD_DEF_RAND_FUN;
	packet->prf = EAP_PWD_DEF_PRF;
	session->token = fr_rand();
	memcpy(packet->token, (char *)&session->token, 4);
	packet->prep = EAP_PWD_PREP_NONE;
	memcpy(packet->identity, inst->server_id, session->out_len - sizeof(pwd_id_packet_t) );

	handler->stage = PROCESS;

	return send_pwd_request(session, handler->eap_ds);
}
/*
 *	mschap_authenticate() - authenticate user based on given
 *	attributes and configuration.
 *	We will try to find out password in configuration
 *	or in configured passwd file.
 *	If one is found we will check paraneters given by NAS.
 *
 *	If PW_SMB_ACCOUNT_CTRL is not set to ACB_PWNOTREQ we must have
 *	one of:
 *		PAP:      PW_USER_PASSWORD or
 *		MS-CHAP:  PW_MSCHAP_CHALLENGE and PW_MSCHAP_RESPONSE or
 *		MS-CHAP2: PW_MSCHAP_CHALLENGE and PW_MSCHAP2_RESPONSE
 *	In case of password mismatch or locked account we MAY return
 *	PW_MSCHAP_ERROR for MS-CHAP or MS-CHAP v2
 *	If MS-CHAP2 succeeds we MUST return
 *	PW_MSCHAP2_SUCCESS
 */
static int mschap_authenticate(void * instance, REQUEST *request)
{
#define inst ((rlm_mschap_t *)instance)
	VALUE_PAIR *challenge = NULL;
	VALUE_PAIR *response = NULL;
	VALUE_PAIR *password = NULL;
	VALUE_PAIR *lm_password, *nt_password, *smb_ctrl;
	VALUE_PAIR *username;
	uint8_t nthashhash[16];
	char msch2resp[42];
	char *username_string;
	int chap = 0;
	int		do_ntlm_auth;

	/*
	 *	If we have ntlm_auth configured, use it unless told
	 *	otherwise
	 */
	do_ntlm_auth = (inst->ntlm_auth != NULL);

	/*
	 *	If we have an ntlm_auth configuration, then we may
	 *	want to suppress it.
	 */
	if (do_ntlm_auth) {
		VALUE_PAIR *vp = pairfind(request->config_items,
					  PW_MS_CHAP_USE_NTLM_AUTH);
		if (vp) do_ntlm_auth = vp->vp_integer;
	}

	/*
	 *	Find the SMB-Account-Ctrl attribute, or the
	 *	SMB-Account-Ctrl-Text attribute.
	 */
	smb_ctrl = pairfind(request->config_items, PW_SMB_ACCOUNT_CTRL);
	if (!smb_ctrl) {
		password = pairfind(request->config_items,
				    PW_SMB_ACCOUNT_CTRL_TEXT);
		if (password) {
			smb_ctrl = radius_pairmake(request,
						   &request->config_items,
						   "SMB-Account-CTRL", "0",
						   T_OP_SET);
			if (smb_ctrl) {
				smb_ctrl->vp_integer = pdb_decode_acct_ctrl(password->vp_strvalue);
			}
		}
	}

	/*
	 *	We're configured to do MS-CHAP authentication.
	 *	and account control information exists.  Enforce it.
	 */
	if (smb_ctrl) {
		/*
		 *	Password is not required.
		 */
		if ((smb_ctrl->vp_integer & ACB_PWNOTREQ) != 0) {
			RDEBUG2("SMB-Account-Ctrl says no password is required.");
			return RLM_MODULE_OK;
		}
	}

	/*
	 *	Decide how to get the passwords.
	 */
	password = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD);

	/*
	 *	We need an LM-Password.
	 */
	lm_password = pairfind(request->config_items, PW_LM_PASSWORD);
	if (lm_password) {
		/*
		 *	Allow raw octets.
		 */
		if ((lm_password->length == 16) ||
		    ((lm_password->length == 32) &&
		     (fr_hex2bin(lm_password->vp_strvalue,
				 lm_password->vp_octets, 16) == 16))) {
			RDEBUG2("Found LM-Password");
			lm_password->length = 16;

		} else {
			radlog_request(L_ERR, 0, request, "Invalid LM-Password");
			lm_password = NULL;
		}

	} else if (!password) {
		if (!do_ntlm_auth) RDEBUG2("No Cleartext-Password configured.  Cannot create LM-Password.");

	} else {		/* there is a configured Cleartext-Password */
		lm_password = radius_pairmake(request, &request->config_items,
					      "LM-Password", "", T_OP_EQ);
		if (!lm_password) {
			radlog_request(L_ERR, 0, request, "No memory");
		} else {
			smbdes_lmpwdhash(password->vp_strvalue,
					 lm_password->vp_octets);
			lm_password->length = 16;
		}
	}

	/*
	 *	We need an NT-Password.
	 */
	nt_password = pairfind(request->config_items, PW_NT_PASSWORD);
	if (nt_password) {
		if ((nt_password->length == 16) ||
		    ((nt_password->length == 32) &&
		     (fr_hex2bin(nt_password->vp_strvalue,
				 nt_password->vp_octets, 16) == 16))) {
			RDEBUG2("Found NT-Password");
			nt_password->length = 16;

                } else {
			radlog_request(L_ERR, 0, request, "Invalid NT-Password");
			nt_password = NULL;
		}
	} else if (!password) {
		if (!do_ntlm_auth) RDEBUG2("No Cleartext-Password configured.  Cannot create NT-Password.");

	} else {		/* there is a configured Cleartext-Password */
		nt_password = radius_pairmake(request, &request->config_items,
					      "NT-Password", "", T_OP_EQ);
		if (!nt_password) {
			radlog_request(L_ERR, 0, request, "No memory");
			return RLM_MODULE_FAIL;
		} else {
			mschap_ntpwdhash(nt_password->vp_octets,
				  password->vp_strvalue);
			nt_password->length = 16;
		}
	}

	challenge = pairfind(request->packet->vps, PW_MSCHAP_CHALLENGE);
	if (!challenge) {
		RDEBUG("ERROR: You set 'Auth-Type = MS-CHAP' for a request that does not contain any MS-CHAP attributes!");
		return RLM_MODULE_REJECT;
	}

	/*
	 *	We also require an MS-CHAP-Response.
	 */
	response = pairfind(request->packet->vps, PW_MSCHAP_RESPONSE);

	/*
	 *	MS-CHAP-Response, means MS-CHAPv1
	 */
	if (response) {
		int offset;

		/*
		 *	MS-CHAPv1 challenges are 8 octets.
		 */
		if (challenge->length < 8) {
			radlog_request(L_AUTH, 0, request, "MS-CHAP-Challenge has the wrong format.");
			return RLM_MODULE_INVALID;
		}

		/*
		 *	Responses are 50 octets.
		 */
		if (response->length < 50) {
			radlog_request(L_AUTH, 0, request, "MS-CHAP-Response has the wrong format.");
			return RLM_MODULE_INVALID;
		}

		/*
		 *	We are doing MS-CHAP.  Calculate the MS-CHAP
		 *	response
		 */
		if (response->vp_octets[1] & 0x01) {
			RDEBUG2("Client is using MS-CHAPv1 with NT-Password");
			password = nt_password;
			offset = 26;
		} else {
			RDEBUG2("Client is using MS-CHAPv1 with LM-Password");
			password = lm_password;
			offset = 2;
		}

		/*
		 *	Do the MS-CHAP authentication.
		 */
		if (do_mschap(inst, request, password, challenge->vp_octets,
			      response->vp_octets + offset, nthashhash,
			      do_ntlm_auth) < 0) {
			RDEBUG2("MS-CHAP-Response is incorrect.");
			goto do_error;
		}

		chap = 1;

	} else if ((response = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE)) != NULL) {
		uint8_t	mschapv1_challenge[16];
		VALUE_PAIR *name_attr, *response_name;

		/*
		 *	MS-CHAPv2 challenges are 16 octets.
		 */
		if (challenge->length < 16) {
			radlog_request(L_AUTH, 0, request, "MS-CHAP-Challenge has the wrong format.");
			return RLM_MODULE_INVALID;
		}

		/*
		 *	Responses are 50 octets.
		 */
		if (response->length < 50) {
			radlog_request(L_AUTH, 0, request, "MS-CHAP-Response has the wrong format.");
			return RLM_MODULE_INVALID;
		}

		/*
		 *	We also require a User-Name
		 */
		username = pairfind(request->packet->vps, PW_USER_NAME);
		if (!username) {
			radlog_request(L_AUTH, 0, request, "We require a User-Name for MS-CHAPv2");
			return RLM_MODULE_INVALID;
		}

		/*
		 *      Check for MS-CHAP-User-Name and if found, use it
		 *      to construct the MSCHAPv1 challenge.  This is
		 *      set by rlm_eap_mschap to the MS-CHAP Response
		 *      packet Name field.
		 *
		 *	We prefer this to the User-Name in the
		 *	packet.
		 */
		response_name = pairfind(request->packet->vps, PW_MS_CHAP_USER_NAME);
		if (response_name) {
			name_attr = response_name;
		} else {
			name_attr = username;
		}
		
		/*
		 *	with_ntdomain_hack moved here, too.
		 */
		if ((username_string = strchr(name_attr->vp_strvalue, '\\')) != NULL) {
			if (inst->with_ntdomain_hack) {
				username_string++;
			} else {
				RDEBUG2("NT Domain delimeter found, should we have enabled with_ntdomain_hack?");
				username_string = name_attr->vp_strvalue;
			}
		} else {
			username_string = name_attr->vp_strvalue;
		}
		
		if (response_name &&
		    ((username->length != response_name->length) ||
		     (strncasecmp(username->vp_strvalue, response_name->vp_strvalue, username->length) != 0))) {
			RDEBUG("ERROR: User-Name (%s) is not the same as MS-CHAP Name (%s) from EAP-MSCHAPv2", username->vp_strvalue, response_name->vp_strvalue);
			return RLM_MODULE_REJECT;
		}

		/*
		 *	The old "mschapv2" function has been moved to
		 *	here.
		 *
		 *	MS-CHAPv2 takes some additional data to create an
		 *	MS-CHAPv1 challenge, and then does MS-CHAPv1.
		 */
		RDEBUG2("Creating challenge hash with username: %s",
			username_string);
		mschap_challenge_hash(response->vp_octets + 2, /* peer challenge */
			       challenge->vp_octets, /* our challenge */
			       username_string,	/* user name */
			       mschapv1_challenge); /* resulting challenge */

		RDEBUG2("Client is using MS-CHAPv2 for %s, we need NT-Password",
		       username_string);

#ifdef __APPLE__
		if (inst->open_directory) {
			return do_od_mschap(request, response, challenge, username_string);
		}
#endif

		if (do_mschap(inst, request, nt_password, mschapv1_challenge,
			      response->vp_octets + 26, nthashhash,
			      do_ntlm_auth) < 0) {
			int i;
			char buffer[128];

			RDEBUG2("FAILED: MS-CHAP2-Response is incorrect");

		do_error:
			snprintf(buffer, sizeof(buffer), "E=691 R=%d",
				 inst->allow_retry);

			if (inst->retry_msg) {
				snprintf(buffer + 9, sizeof(buffer) - 9, " C=");
				for (i = 0; i < 16; i++) {
					snprintf(buffer + 12 + i*2,
						 sizeof(buffer) - 12 - i*2, "%02x",
						 fr_rand() & 0xff);
				}
				snprintf(buffer + 44, sizeof(buffer) - 44,
					 " V=3 M=%s", inst->retry_msg);
			}
			mschap_add_reply(request, &request->reply->vps,
					 *response->vp_octets, "MS-CHAP-Error",
					 buffer, strlen(buffer));
			return RLM_MODULE_REJECT;
		}

		mschap_auth_response(username_string, /* without the domain */
			      nthashhash, /* nt-hash-hash */
			      response->vp_octets + 26, /* peer response */
			      response->vp_octets + 2, /* peer challenge */
			      challenge->vp_octets, /* our challenge */
			      msch2resp); /* calculated MPPE key */
		mschap_add_reply(request, &request->reply->vps, *response->vp_octets,
				 "MS-CHAP2-Success", msch2resp, 42);
		chap = 2;

	} else {		/* Neither CHAPv1 or CHAPv2 response: die */
		RDEBUG("ERROR: You set 'Auth-Type = MS-CHAP' for a request that does not contain any MS-CHAP attributes!");
		return RLM_MODULE_INVALID;
	}

	/*
	 *	We have a CHAP response, but the account may be
	 *	disabled.  Reject the user with the same error code
	 *	we use when their password is invalid.
	 */
	if (smb_ctrl) {
		/*
		 *	Account is disabled.
		 *
		 *	They're found, but they don't exist, so we
		 *	return 'not found'.
		 */
		if (((smb_ctrl->vp_integer & ACB_DISABLED) != 0) ||
		    ((smb_ctrl->vp_integer & (ACB_NORMAL|ACB_WSTRUST)) == 0)) {
			RDEBUG2("SMB-Account-Ctrl says that the account is disabled, or is not a normal or workstatin trust account.");
			mschap_add_reply(request, &request->reply->vps,
					  *response->vp_octets,
					  "MS-CHAP-Error", "E=691 R=1", 9);
			return RLM_MODULE_NOTFOUND;
		}

		/*
		 *	User is locked out.
		 */
		if ((smb_ctrl->vp_integer & ACB_AUTOLOCK) != 0) {
			RDEBUG2("SMB-Account-Ctrl says that the account is locked out.");
			mschap_add_reply(request, &request->reply->vps,
					  *response->vp_octets,
					  "MS-CHAP-Error", "E=647 R=0", 9);
			return RLM_MODULE_USERLOCK;
		}
	}

	/* now create MPPE attributes */
	if (inst->use_mppe) {
		uint8_t mppe_sendkey[34];
		uint8_t mppe_recvkey[34];

		if (chap == 1){
			RDEBUG2("adding MS-CHAPv1 MPPE keys");
			memset(mppe_sendkey, 0, 32);
			if (lm_password) {
				memcpy(mppe_sendkey, lm_password->vp_octets, 8);
			}

			/*
			 *	According to RFC 2548 we
			 *	should send NT hash.  But in
			 *	practice it doesn't work.
			 *	Instead, we should send nthashhash
			 *
			 *	This is an error on RFC 2548.
			 */
			/*
			 *	do_mschap cares to zero nthashhash if NT hash
			 *	is not available.
			 */
			memcpy(mppe_sendkey + 8,
			       nthashhash, 16);
			mppe_add_reply(request,
				       "MS-CHAP-MPPE-Keys",
				       mppe_sendkey, 32);
		} else if (chap == 2) {
			RDEBUG2("adding MS-CHAPv2 MPPE keys");
			mppe_chap2_gen_keys128(nthashhash,
					       response->vp_octets + 26,
					       mppe_sendkey, mppe_recvkey);

			mppe_add_reply(request,
				       "MS-MPPE-Recv-Key",
				       mppe_recvkey, 16);
			mppe_add_reply(request,
				       "MS-MPPE-Send-Key",
				       mppe_sendkey, 16);

		}
		radius_pairmake(request, &request->reply->vps,
				"MS-MPPE-Encryption-Policy",
				(inst->require_encryption)? "0x00000002":"0x00000001",
				T_OP_EQ);
		radius_pairmake(request, &request->reply->vps,
				"MS-MPPE-Encryption-Types",
				(inst->require_strong)? "0x00000004":"0x00000006",
				T_OP_EQ);
	} /* else we weren't asked to use MPPE */

	return RLM_MODULE_OK;
#undef inst
}
Ejemplo n.º 12
0
/** Authenticate a previously sent challenge
 *
 */
static rlm_rcode_t mod_process(UNUSED void *instance, eap_session_t *eap_session)
{
	REQUEST			*request = eap_session->request;
	eap_sim_session_t	*eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t);
	fr_sim_decode_ctx_t	ctx = {
					.keys = &eap_sim_session->keys,
				};
	VALUE_PAIR		*subtype_vp, *from_peer, *vp;
	fr_cursor_t		cursor;

	eap_sim_subtype_t	subtype;

	int			ret;

	/*
	 *	VPS is the data from the client
	 */
	from_peer = eap_session->request->packet->vps;

	fr_cursor_init(&cursor, &request->packet->vps);
	fr_cursor_tail(&cursor);

	ret = fr_sim_decode(eap_session->request,
			    &cursor,
			    dict_eap_sim,
			    eap_session->this_round->response->type.data,
			    eap_session->this_round->response->type.length,
			    &ctx);
	/*
	 *	RFC 4186 says we *MUST* notify, not just
	 *	send an EAP-Failure in this case where
	 *	we cannot decode an EAP-AKA packet.
	 */
	if (ret < 0) {
		RPEDEBUG2("Failed decoding EAP-SIM attributes");
		eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
		return RLM_MODULE_HANDLED;	/* We need to process more packets */
	}

	vp = fr_cursor_current(&cursor);
	if (vp && RDEBUG_ENABLED2) {
		RDEBUG2("Decoded EAP-SIM attributes");
		log_request_pair_list(L_DBG_LVL_2, request, vp, NULL);
	}

	subtype_vp = fr_pair_find_by_da(from_peer, attr_eap_sim_subtype, TAG_ANY);
	if (!subtype_vp) {
		REDEBUG("Missing EAP-SIM-Subtype");
		eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
		return RLM_MODULE_HANDLED;				/* We need to process more packets */
	}
	subtype = subtype_vp->vp_uint16;

	switch (eap_sim_session->state) {
	/*
	 *	Response to our advertised versions and request for an ID
	 *	This is very similar to Identity negotiation in EAP-AKA[']
	 */
	case EAP_SIM_SERVER_START:
		switch (subtype) {
		case EAP_SIM_START:
			if (process_eap_sim_start(eap_session, from_peer) == 0) return RLM_MODULE_HANDLED;
			eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
			return RLM_MODULE_HANDLED;	/* We need to process more packets */

		/*
		 *	Case 1 where we're allowed to send an EAP-Failure
		 *
		 *	This can happen in the case of a conservative
		 *	peer, where it refuses to provide the permanent
		 *	identity.
		 */
		case EAP_SIM_CLIENT_ERROR:
		{
			char buff[20];

			vp = fr_pair_find_by_da(from_peer, attr_eap_sim_client_error_code, TAG_ANY);
			if (!vp) {
				REDEBUG("EAP-SIM Peer rejected SIM-Start (%s) with client-error message but "
					"has not supplied a client error code",
					fr_int2str(sim_id_request_table, eap_sim_session->id_req, "<INVALID>"));
			} else {
				REDEBUG("Client rejected SIM-Start (%s) with error: %s (%i)",
					fr_int2str(sim_id_request_table, eap_sim_session->id_req, "<INVALID>"),
					fr_pair_value_enum(vp, buff), vp->vp_uint16);
			}
			eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE);
			return RLM_MODULE_REJECT;
		}

		case EAP_SIM_NOTIFICATION:
		notification:
		{
			char buff[20];

			vp = fr_pair_afrom_da(from_peer, attr_eap_sim_notification);
			if (!vp) {
				REDEBUG2("Received SIM-Notification with no notification code");
				eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
				return RLM_MODULE_HANDLED;			/* We need to process more packets */
			}

			/*
			 *	Case 2 where we're allowed to send an EAP-Failure
			 */
			if (!(vp->vp_uint16 & 0x8000)) {
				REDEBUG2("SIM-Notification %s (%i) indicates failure", fr_pair_value_enum(vp, buff),
					 vp->vp_uint16);
				eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE);
				return RLM_MODULE_REJECT;
			}

			/*
			 *	...if it's not a failure, then re-enter the
			 *	current state.
			 */
			REDEBUG2("Got SIM-Notification %s (%i)", fr_pair_value_enum(vp, buff), vp->vp_uint16);
			eap_sim_state_enter(eap_session, eap_sim_session->state);
			return RLM_MODULE_HANDLED;

		default:
		unexpected_subtype:
			/*
			 *	RFC 4186 says we *MUST* notify, not just
			 *	send an EAP-Failure in this case.
			 */
			REDEBUG("Unexpected subtype %pV", &subtype_vp->data);
			eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
			return RLM_MODULE_HANDLED;				/* We need to process more packets */
		}
		}

	/*
	 *	Process the response to our previous challenge.
	 */
	case EAP_SIM_SERVER_CHALLENGE:
		switch (subtype) {
		/*
		 *	A response to our EAP-Sim/Request/Challenge!
		 */
		case EAP_SIM_CHALLENGE:
			switch (process_eap_sim_challenge(eap_session, from_peer)) {
			case 1:
				return RLM_MODULE_HANDLED;

			case 0:
				return RLM_MODULE_OK;

			case -1:
				eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
				return RLM_MODULE_HANDLED;			/* We need to process more packets */
			}

		case EAP_SIM_CLIENT_ERROR:
		{
			char buff[20];

			vp = fr_pair_find_by_da(from_peer, attr_eap_sim_client_error_code, TAG_ANY);
			if (!vp) {
				REDEBUG("EAP-SIM Peer rejected SIM-Challenge with client-error message but "
					"has not supplied a client error code");
			} else {
				REDEBUG("Client rejected SIM-Challenge with error: %s (%i)",
					fr_pair_value_enum(vp, buff), vp->vp_uint16);
			}
			eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE);
			return RLM_MODULE_REJECT;
		}

		case EAP_SIM_NOTIFICATION:
			goto notification;

		default:
			goto unexpected_subtype;
		}

	/*
	 *	Peer acked our failure
	 */
	case EAP_SIM_SERVER_FAILURE_NOTIFICATION:
		switch (subtype) {
		case EAP_SIM_NOTIFICATION:
			RDEBUG2("SIM-Notification ACKed, sending EAP-Failure");
			eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE);
			return RLM_MODULE_REJECT;

		default:
			goto unexpected_subtype;
		}

	/*
	 *	Something bad happened...
	 */
	default:
		rad_assert(0);
		eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION);
		return RLM_MODULE_HANDLED;				/* We need to process more packets */
	}
}

/*
 *	Initiate the EAP-SIM session by starting the state machine
 *      and initiating the state.
 */
static rlm_rcode_t mod_session_init(void *instance, eap_session_t *eap_session)
{
	REQUEST				*request = eap_session->request;
	eap_sim_session_t		*eap_sim_session;
	rlm_eap_sim_t			*inst = instance;
	fr_sim_id_type_t		type;
	fr_sim_method_hint_t		method;

	MEM(eap_sim_session = talloc_zero(eap_session, eap_sim_session_t));

	eap_session->opaque = eap_sim_session;

	/*
	 *	Set default configuration, we may allow these
	 *	to be toggled by attributes later.
	 */
	eap_sim_session->send_result_ind = inst->protected_success;
	eap_sim_session->id_req = SIM_ANY_ID_REQ;	/* Set the default */

	/*
	 *	This value doesn't have be strong, but it is
	 *	good if it is different now and then.
	 */
	eap_sim_session->sim_id = (fr_rand() & 0xff);

	/*
	 *	Save the keying material, because it could change on a subsequent retrieval.
	 */
	RDEBUG2("New EAP-SIM session");

	/*
	 *	Process the identity that we received in the
	 *	EAP-Identity-Response and use it to determine
	 *	the initial request we send to the Supplicant.
	 */
	if (fr_sim_id_type(&type, &method,
			   eap_session->identity, talloc_array_length(eap_session->identity) - 1) < 0) {
		RPWDEBUG2("Failed parsing identity, continuing anyway");
	}

	switch (method) {
	default:
		RWDEBUG("EAP-Identity-Response hints that EAP-%s should be started, but we're attempting EAP-SIM",
			fr_int2str(sim_id_method_hint_table, method, "<INVALID>"));
		break;

	case SIM_METHOD_HINT_SIM:
	case SIM_METHOD_HINT_UNKNOWN:
		break;
	}
	eap_session->process = mod_process;

	/*
	 *	Figure out what type of identity we have
	 *	and use it to determine the initial
	 *	request we send.
	 */
	switch (type) {
	/*
	 *	These types need to be transformed into something
	 *	usable before we can do anything.
	 */
	case SIM_ID_TYPE_UNKNOWN:
	case SIM_ID_TYPE_PSEUDONYM:
	case SIM_ID_TYPE_FASTAUTH:
	/*
	 *	Permanent ID means we can just send the challenge
	 */
	case SIM_ID_TYPE_PERMANENT:
		eap_sim_session->keys.identity_len = talloc_array_length(eap_session->identity) - 1;
		MEM(eap_sim_session->keys.identity = talloc_memdup(eap_sim_session, eap_session->identity,
								   eap_sim_session->keys.identity_len));
		eap_sim_state_enter(eap_session, EAP_SIM_SERVER_START);
		return RLM_MODULE_HANDLED;
	}

	return RLM_MODULE_HANDLED;
}
static int eap_sim_get_challenge(eap_handler_t *handler, VALUE_PAIR *vps, int idx, eap_sim_state_t *ess)
{
	REQUEST *request = handler->request;
	VALUE_PAIR *vp, *ki, *algo_version;

	rad_assert(idx >= 0 && idx < 3);

	/*
	 *	Generate a new RAND value, and derive Kc and SRES from Ki
	 */
	ki = pairfind(vps, PW_EAP_SIM_KI, 0, TAG_ANY);
	if (ki) {
		int i;

		/*
		 *	Check to see if have a Ki for the IMSI, this allows us to generate the rest
		 *	of the triplets.
		 */
		algo_version = pairfind(vps, PW_EAP_SIM_ALGO_VERSION, 0, TAG_ANY);
		if (!algo_version) {
			REDEBUG("Found Ki, but missing EAP-Sim-Algo-Version");
			return 0;
		}

		for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
			ess->keys.rand[idx][i] = fr_rand();
		}

		switch (algo_version->vp_integer) {
		case 1:
			comp128v1(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx]);
			break;

		case 2:
			comp128v23(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx],
				   true);
			break;

		case 3:
			comp128v23(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx],
				   false);
			break;

		case 4:
			REDEBUG("Comp128-4 algorithm is not supported as details have not yet been published. "
				"If you have details of this algorithm please contact the FreeRADIUS "
				"maintainers");
			return 0;

		default:
			REDEBUG("Unknown/unsupported algorithm Comp128-%i", algo_version->vp_integer);
		}

		if (RDEBUG_ENABLED2) {
			char buffer[33];	/* 32 hexits (16 bytes) + 1 */
			char *p;

			RDEBUG2("Generated following triplets for round %i:", idx);

			p = buffer;
			for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
				p += sprintf(p, "%02x", ess->keys.rand[idx][i]);
			}
			RDEBUG2("\tRAND : 0x%s", buffer);

			p = buffer;
			for (i = 0; i < EAPSIM_SRES_SIZE; i++) {
				p += sprintf(p, "%02x", ess->keys.sres[idx][i]);
			}
			RDEBUG2("\tSRES : 0x%s", buffer);

			p = buffer;
			for (i = 0; i < EAPSIM_KC_SIZE; i++) {
				p += sprintf(p, "%02x", ess->keys.Kc[idx][i]);
			}
			RDEBUG2("\tKc   : 0x%s", buffer);
		}
		return 1;
	}

	/*
	 *	Use known RAND, SRES, and Kc values, these may of been pulled in from an AuC,
	 *	or created by sending challenges to the SIM directly.
	 */
	vp = pairfind(vps, PW_EAP_SIM_RAND1 + idx, 0, TAG_ANY);
	if (!vp) {
		/* bad, we can't find stuff! */
		REDEBUG("control:EAP-SIM-RAND%i not found", idx + 1);
		return 0;
	}
	if (vp->length != EAPSIM_RAND_SIZE) {
		REDEBUG("control:EAP-SIM-RAND%i is not " STRINGIFY(EAPSIM_RAND_SIZE) " bytes, got %zu bytes",
			idx + 1, vp->length);
		return 0;
	}
	memcpy(ess->keys.rand[idx], vp->vp_octets, EAPSIM_RAND_SIZE);

	vp = pairfind(vps, PW_EAP_SIM_SRES1 + idx, 0, TAG_ANY);
	if (!vp) {
		/* bad, we can't find stuff! */
		REDEBUG("control:EAP-SIM-SRES%i not found", idx + 1);
		return 0;
	}
	if (vp->length != EAPSIM_SRES_SIZE) {
		REDEBUG("control:EAP-SIM-SRES%i is not " STRINGIFY(EAPSIM_SRES_SIZE) " bytes, got %zu bytes",
			idx + 1, vp->length);
		return 0;
	}
	memcpy(ess->keys.sres[idx], vp->vp_octets, EAPSIM_SRES_SIZE);

	vp = pairfind(vps, PW_EAP_SIM_KC1 + idx, 0, TAG_ANY);
	if (!vp) {
		/* bad, we can't find stuff! */
		REDEBUG("control:EAP-SIM-Kc%i not found", idx + 1);
		return 0;
	}
	if (vp->length != EAPSIM_KC_SIZE) {
		REDEBUG("control:EAP-SIM-Kc%i is not 8 bytes, got %zu bytes", idx + 1, vp->length);
		return 0;
	}
	memcpy(ess->keys.Kc[idx], vp->vp_octets, EAPSIM_KC_SIZE);
	if (vp->length != EAPSIM_KC_SIZE) {
		REDEBUG("control:EAP-SIM-Kc%i is not " STRINGIFY(EAPSIM_KC_SIZE) " bytes, got %zu bytes",
			idx + 1, vp->length);
		return 0;
	}
	memcpy(ess->keys.Kc[idx], vp->vp_strvalue, EAPSIM_KC_SIZE);

	return 1;
}
Ejemplo n.º 14
0
/** Copy packet to multiple servers
 *
 * Create a duplicate of the packet and send it to a list of realms
 * defined by the presence of the Replicate-To-Realm VP in the control
 * list of the current request.
 *
 * This is pretty hacky and is 100% fire and forget. If you're looking
 * to forward authentication requests to multiple realms and process
 * the responses, this function will not allow you to do that.
 *
 * @param[in] instance 	of this module.
 * @param[in] request 	The current request.
 * @param[in] list	of attributes to copy to the duplicate packet.
 * @param[in] code	to write into the code field of the duplicate packet.
 * @return RCODE fail on error, invalid if list does not exist, noop if no replications succeeded, else ok.
 */
static rlm_rcode_t replicate_packet(UNUSED void *instance, REQUEST *request, pair_lists_t list, PW_CODE code)
{
	int rcode = RLM_MODULE_NOOP;
	bool pass1 = true;

	vp_cursor_t cursor;
	VALUE_PAIR *vp;

	RADIUS_PACKET *packet = NULL;

	rcode = rlm_replicate_alloc(&packet, request, list, code);
	if (rcode != RLM_MODULE_OK) {
		return rcode;
	}

	/*
	 *	Send as many packets as necessary to different destinations.
	 */
	fr_cursor_init(&cursor, &request->config_items);
	while ((vp = fr_cursor_next_by_num(&cursor, PW_REPLICATE_TO_REALM, 0, TAG_ANY))) {
		home_server_t *home;
		REALM *realm;
		home_pool_t *pool;

		realm = realm_find2(vp->vp_strvalue);
		if (!realm) {
			REDEBUG2("Cannot Replicate to unknown realm \"%s\"", vp->vp_strvalue);
			continue;
		}

		/*
		 *	We shouldn't really do this on every loop.
		 */
		switch (request->packet->code) {
		default:
			REDEBUG2("Cannot replicate unknown packet code %d", request->packet->code);
			rcode = RLM_MODULE_FAIL;
			goto done;

		case PW_CODE_ACCESS_REQUEST:
			pool = realm->auth_pool;
			break;

#ifdef WITH_ACCOUNTING

		case PW_CODE_ACCOUNTING_REQUEST:
			pool = realm->acct_pool;
			break;
#endif

#ifdef WITH_COA
		case PW_CODE_COA_REQUEST:
		case PW_CODE_DISCONNECT_REQUEST:
			pool = realm->acct_pool;
			break;
#endif
		}

		if (!pool) {
			RWDEBUG2("Cancelling replication to Realm %s, as the realm is local", realm->name);
			continue;
		}

		home = home_server_ldb(realm->name, pool, request);
		if (!home) {
			REDEBUG2("Failed to find live home server for realm %s", realm->name);
			continue;
		}

		/*
		 *	For replication to multiple servers we re-use the packet
		 *	we built here.
		 */
		if (pass1) {
			packet->id = fr_rand() & 0xff;
			packet->sockfd = fr_socket(&home->src_ipaddr, 0);
			if (packet->sockfd < 0) {
				REDEBUG("Failed opening socket: %s", fr_strerror());
				rcode = RLM_MODULE_FAIL;
				goto done;
			}
			pass1 = false;
		} else {
			size_t i;

			for (i = 0; i < sizeof(packet->vector); i++) {
				packet->vector[i] = fr_rand() & 0xff;
			}

			packet->id++;
			TALLOC_FREE(packet->data);
			packet->data_len = 0;
		}

		/*
		 *	(Re)-Write these.
		 */
		packet->dst_ipaddr = home->ipaddr;
		packet->dst_port = home->port;
		memset(&packet->src_ipaddr, 0, sizeof(packet->src_ipaddr));
		packet->src_port = 0;

		/*
		 *	Encode, sign and then send the packet.
		 */
		RDEBUG("Replicating list '%s' to Realm '%s'", fr_int2str(pair_lists, list, "<INVALID>"), realm->name);
		if (rad_send(packet, NULL, home->secret) < 0) {
			REDEBUG("Failed replicating packet: %s", fr_strerror());
			rcode = RLM_MODULE_FAIL;
			goto done;
		}

		/*
		 *	We've sent it to at least one destination.
		 */
		rcode = RLM_MODULE_OK;
	}

	done:

	talloc_free(packet);
	return rcode;
}
/*
 *	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;
}
Ejemplo n.º 16
0
/*
 *	Initiate the EAP-MD5 session by sending a challenge to the peer.
 */
static int md5_initiate(void *type_data, EAP_HANDLER *handler)
{
    int		i;
    MD5_PACKET	*reply;

    type_data = type_data;	/* -Wunused */

    /*
     *	Allocate an EAP-MD5 packet.
     */
    reply = eapmd5_alloc();
    if (reply == NULL)  {
        radlog(L_ERR, "rlm_eap_md5: out of memory");
        return 0;
    }

    /*
     *	Fill it with data.
     */
    reply->code = PW_MD5_CHALLENGE;
    reply->length = 1 + MD5_CHALLENGE_LEN; /* one byte of value size */
    reply->value_size = MD5_CHALLENGE_LEN;

    /*
     *	Allocate user data.
     */
    reply->value = malloc(reply->value_size);
    if (reply->value == NULL) {
        radlog(L_ERR, "rlm_eap_md5: out of memory");
        eapmd5_free(&reply);
        return 0;
    }

    /*
     *	Get a random challenge.
     */
    for (i = 0; i < reply->value_size; i++) {
        reply->value[i] = fr_rand();
    }
    DEBUG2("rlm_eap_md5: Issuing Challenge");

    /*
     *	Keep track of the challenge.
     */
    handler->opaque = malloc(reply->value_size);
    rad_assert(handler->opaque != NULL);
    memcpy(handler->opaque, reply->value, reply->value_size);
    handler->free_opaque = free;

    /*
     *	Compose the EAP-MD5 packet out of the data structure,
     *	and free it.
     */
    eapmd5_compose(handler->eap_ds, reply);

    /*
     *	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;
}
Ejemplo n.º 17
0
/** Send a message on the "best" channel.
 *
 * @param nr the network
 * @param cd the message we've received
 */
static bool fr_network_send_request(fr_network_t *nr, fr_channel_data_t *cd)
{
	fr_network_worker_t *worker;
	fr_channel_data_t *reply;

	(void) talloc_get_type_abort(nr, fr_network_t);

	if (nr->num_workers == 1) {
		worker = nr->workers[0];

	} else {
		uint32_t one, two;

		if (nr->num_workers == 2) {
			one = 0;
			two = 1;
		} else {
			one = fr_rand() % nr->num_workers;
			do {
				two = fr_rand() % nr->num_workers;
			} while (two == one);
		}

		if (nr->workers[one]->cpu_time < nr->workers[two]->cpu_time) {
			worker = nr->workers[one];
		} else {
			worker = nr->workers[two];
		}
	}

	(void) talloc_get_type_abort(worker, fr_network_worker_t);

	/*
	 *	Send the message to the channel.  If we fail, drop the
	 *	packet.  The only reason for failure is that the
	 *	worker isn't servicing it's input queue.  When that
	 *	happens, we have no idea what to do, and the whole
	 *	thing falls over.
	 */
	if (fr_channel_send_request(worker->channel, cd, &reply) < 0) {
		worker->stats.dropped++;
		return false;
	}

	worker->stats.in++;

	/*
	 *	We're projecting that the worker will use more CPU
	 *	time to process this request.  The CPU time will be
	 *	updated with a more accurate number when we receive a
	 *	reply from this channel.
	 */
	worker->cpu_time += worker->predicted;

	/*
	 *	If we have a reply, push it onto our local queue, and
	 *	poll for more replies.
	 */
	if (reply) fr_network_drain_input(nr, worker->channel, reply);

	return true;
}
Ejemplo n.º 18
0
/*
 *	Send one packet.
 */
static int send_one_packet(rc_request_t *request)
{
	assert(request->done == false);

	/*
	 *	Remember when we have to wake up, to re-send the
	 *	request, of we didn't receive a reply.
	 */
	if ((sleep_time == -1) || (sleep_time > (int) timeout)) {
		sleep_time = (int) timeout;
	}

	/*
	 *	Haven't sent the packet yet.  Initialize it.
	 */
	if (request->packet->id == -1) {
		int i;
		bool rcode;

		assert(request->reply == NULL);

		/*
		 *	Didn't find a free packet ID, we're not done,
		 *	we don't sleep, and we stop trying to process
		 *	this packet.
		 */
	retry:
		request->packet->src_ipaddr.af = server_ipaddr.af;
		rcode = fr_packet_list_id_alloc(pl, ipproto,
						&request->packet, NULL);
		if (!rcode) {
			int mysockfd;

#ifdef WITH_TCP
			if (proto) {
				mysockfd = fr_tcp_client_socket(NULL,
								&server_ipaddr,
								server_port);
			} else
#endif
			mysockfd = fr_socket(&client_ipaddr, 0);
			if (mysockfd < 0) {
				ERROR("Can't open new socket: %s", strerror(errno));
				exit(1);
			}
			if (!fr_packet_list_socket_add(pl, mysockfd, ipproto,
						       &server_ipaddr,
						       server_port, NULL)) {
				ERROR("Can't add new socket");
				exit(1);
			}
			goto retry;
		}

		assert(request->packet->id != -1);
		assert(request->packet->data == NULL);

		for (i = 0; i < 4; i++) {
			((uint32_t *) request->packet->vector)[i] = fr_rand();
		}

		/*
		 *	Update the password, so it can be encrypted with the
		 *	new authentication vector.
		 */
		if (request->password[0] != '\0') {
			VALUE_PAIR *vp;

			if ((vp = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) {
				pairstrcpy(vp, request->password);

			} else if ((vp = pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) {
				bool already_hex = false;

				/*
				 *	If it's 17 octets, it *might* be already encoded.
				 *	Or, it might just be a 17-character password (maybe UTF-8)
				 *	Check it for non-printable characters.  The odds of ALL
				 *	of the characters being 32..255 is (1-7/8)^17, or (1/8)^17,
				 *	or 1/(2^51), which is pretty much zero.
				 */
				if (vp->length == 17) {
					for (i = 0; i < 17; i++) {
						if (vp->vp_octets[i] < 32) {
							already_hex = true;
							break;
						}
					}
				}

				/*
				 *	Allow the user to specify ASCII or hex CHAP-Password
				 */
				if (!already_hex) {
					uint8_t *p;
					size_t len, len2;

					len = len2 = strlen(request->password);
					if (len2 < 17) len2 = 17;

					p = talloc_zero_array(vp, uint8_t, len2);

					memcpy(p, request->password, len);

					rad_chap_encode(request->packet,
							p,
							fr_rand() & 0xff, vp);
					vp->vp_octets = p;
					vp->length = 17;
				}
			} else if (pairfind(request->packet->vps, PW_MSCHAP_PASSWORD, 0, TAG_ANY) != NULL) {
				mschapv1_encode(request->packet,
						&request->packet->vps,
						request->password);
			} else {
				DEBUG("WARNING: No password in the request");
			}
		}

		request->timestamp = time(NULL);
		request->tries = 1;
		request->resend++;

#ifdef WITH_TCP
		/*
		 *	WTF?
		 */
		if (client_port == 0) {
			client_ipaddr = request->packet->src_ipaddr;
			client_port = request->packet->src_port;
		}
#endif

	} else {		/* request->packet->id >= 0 */
		time_t now = time(NULL);

		/*
		 *	FIXME: Accounting packets are never retried!
		 *	The Acct-Delay-Time attribute is updated to
		 *	reflect the delay, and the packet is re-sent
		 *	from scratch!
		 */

		/*
		 *	Not time for a retry, do so.
		 */
		if ((now - request->timestamp) < timeout) {
			/*
			 *	When we walk over the tree sending
			 *	packets, we update the minimum time
			 *	required to sleep.
			 */
			if ((sleep_time == -1) ||
			    (sleep_time > (now - request->timestamp))) {
				sleep_time = now - request->timestamp;
			}
			return 0;
		}

		/*
		 *	We're not trying later, maybe the packet is done.
		 */
		if (request->tries == retries) {
			assert(request->packet->id >= 0);

			/*
			 *	Delete the request from the tree of
			 *	outstanding requests.
			 */
			fr_packet_list_yank(pl, request->packet);

			REDEBUG("No reply from server for ID %d socket %d",
				request->packet->id, request->packet->sockfd);
			deallocate_id(request);

			/*
			 *	Normally we mark it "done" when we've received
			 *	the reply, but this is a special case.
			 */
			if (request->resend == resend_count) {
				request->done = true;
			}
			stats.lost++;
			return -1;
		}

		/*
		 *	We are trying later.
		 */
		request->timestamp = now;
		request->tries++;
	}

	/*
	 *	Send the packet.
	 */
	if (rad_send(request->packet, NULL, secret) < 0) {
		REDEBUG("Failed to send packet for ID %d", request->packet->id);
	}

	return 0;
}
Ejemplo n.º 19
0
/**
 *  @brief Generate a string of random chars
 *
 *  Build strings of random chars, useful for generating tokens and passcodes
 *  Format similar to String::Random.
 */
static size_t randstr_xlat(UNUSED void *instance, REQUEST *request,
			   char *fmt, char *out, size_t outlen,
			   RADIUS_ESCAPE_STRING func)
{
	char		*p;
	char		buffer[1024];
	unsigned int	result;
	size_t		freespace = outlen;
	size_t		len;

	if (outlen <= 1) return 0;

	/*
	 * Do an xlat on the provided string (nice recursive operation).
	 */
	len = radius_xlat(buffer, sizeof(buffer), fmt, request, func);
	if (!len) {
		radlog(L_ERR, "rlm_expr: xlat failed.");
		*out = '\0';
		return 0;
	}

	p = buffer;
	while ((len-- > 0) && (--freespace > 0)) {
		result = fr_rand();
		switch (*p) {
			/*
			 *  Lowercase letters
			 */
			case 'c':
				*out++ = 'a' + (result % 26);
			break;

			/*
			 *  Uppercase letters
			 */
			case 'C':
				*out++ = 'A' + (result % 26);
			break;

			/*
			 *  Numbers
			 */
			case 'n':
				*out++ = '0' + (result % 10);
			break;

			/*
			 *  Alpha numeric
			 */
			case 'a':
				*out++ = randstr_salt[result % (sizeof(randstr_salt) - 3)];
			break;

			/*
			 *  Punctuation
			 */
			case '!':
				*out++ = randstr_punc[result % (sizeof(randstr_punc) - 1)];
			break;

			/*
			 *  Alpa numeric + punctuation
			 */
			case '.':
				*out++ = '!' + (result % 95);
			break;

			/*
			 *  Alpha numeric + salt chars './'
			 */
			case 's':
				*out++ = randstr_salt[result % (sizeof(randstr_salt) - 1)];
			break;

			/*
			 *  Binary data as hexits (we don't really support
			 *  non printable chars).
			 */
			case 'h':
				if (freespace < 2)
					break;

				snprintf(out, 3, "%02x", result % 256);

				/* Already decremented */
				freespace -= 1;
				out += 2;
			break;

			default:
				radlog(L_ERR,
				       "rlm_expr: invalid character class '%c'",
				       *p);

				return 0;
			break;
		}

		p++;
	}

	*out++ = '\0';

	return outlen - freespace;
}
Ejemplo n.º 20
0
static int vector_umts_from_ki(eap_session_t *eap_session, VALUE_PAIR *vps, fr_sim_keys_t *keys)
{
	REQUEST		*request = eap_session->request;
	VALUE_PAIR	*ki_vp, *amf_vp, *sqn_vp, *version_vp;

	uint64_t	sqn;
	uint8_t		amf_buff[MILENAGE_AMF_SIZE] = { 0x00, 0x00 };
	uint8_t 	opc_buff[MILENAGE_OPC_SIZE];
	uint8_t	const	*opc_p;
	uint32_t	version = 4;
	int		i;

	ki_vp = fr_pair_find_by_da(vps, attr_sim_ki, TAG_ANY);
	if (!ki_vp) {
		RDEBUG3("No &control:%s found, not generating quintuplets locally", attr_sim_ki->name);
		return 1;
	} else if (ki_vp->vp_length != MILENAGE_KI_SIZE) {
		REDEBUG("&control:%s has incorrect length, expected %u bytes got %zu bytes",
			attr_sim_ki->name, MILENAGE_KI_SIZE, ki_vp->vp_length);
		return -1;
	}

	if (vector_opc_from_op(request, &opc_p, opc_buff, vps, ki_vp->vp_octets) < 0) return -1;

	amf_vp = fr_pair_find_by_da(vps, attr_sim_amf, TAG_ANY);
	if (amf_vp) {
		if (amf_vp->vp_length != sizeof(amf_buff)) {
			REDEBUG("&control:%s has incorrect length, expected %u bytes got %zu bytes",
				attr_sim_amf->name, MILENAGE_AMF_SIZE, amf_vp->vp_length);
			return -1;
		}
		memcpy(amf_buff, amf_vp->vp_octets, sizeof(amf_buff));
	}

	sqn_vp = fr_pair_find_by_da(vps, attr_sim_sqn, TAG_ANY);
	sqn = sqn_vp ? sqn_vp->vp_uint64 : 2;

	/*
	 *	We default to milenage
	 */
	version_vp = fr_pair_find_by_da(vps, attr_sim_algo_version, TAG_ANY);
	if (version_vp) version = version_vp->vp_uint32;

	for (i = 0; i < SIM_VECTOR_UMTS_RAND_SIZE; i += sizeof(uint32_t)) {
		uint32_t rand = fr_rand();
		memcpy(&keys->umts.vector.rand[i], &rand, sizeof(rand));
	}

	switch (version) {
	case 4:
	{
		uint8_t sqn_buff[MILENAGE_SQN_SIZE];

		keys->sqn = sqn_vp ? sqn_vp->vp_uint64 : 0;
		uint48_to_buff(sqn_buff, keys->sqn);

		RDEBUG3("Milenage inputs");
		RINDENT();
		/*
		 *	Don't change colon indent, matches other messages later...
		 */
		RHEXDUMP_INLINE(L_DBG_LVL_3,
				ki_vp->vp_octets, MILENAGE_KI_SIZE,
				"Ki           :");
		RHEXDUMP_INLINE(L_DBG_LVL_3,
				opc_p, MILENAGE_OPC_SIZE,
				"OPc          :");
		RHEXDUMP_INLINE(L_DBG_LVL_3,
				sqn_buff, MILENAGE_SQN_SIZE,
				"SQN          :");
		RHEXDUMP_INLINE(L_DBG_LVL_3,
				amf_buff, MILENAGE_AMF_SIZE,
				"AMF          :");
		REXDENT();

		if (milenage_umts_generate(keys->umts.vector.autn,
					   keys->umts.vector.ik,
					   keys->umts.vector.ck,
					   keys->umts.vector.ak,
					   keys->umts.vector.xres,
					   opc_p,
					   amf_buff,
					   ki_vp->vp_octets,
					   sqn,
					   keys->umts.vector.rand) < 0) {
			RPEDEBUG2("Failed deriving UMTS Quintuplet");
			return -1;
		}

		keys->umts.vector.xres_len = 8;
	}
		return 0;

	case 1:
	case 2:
	case 3:
		REDEBUG("Only Milenage can be used to generate quintuplets");
		return -1;

	default:
		REDEBUG("Unknown/unsupported algorithm %i", version);
		return -1;
	}
}
Ejemplo n.º 21
0
static int vector_gsm_from_ki(eap_session_t *eap_session, VALUE_PAIR *vps, int idx, fr_sim_keys_t *keys)
{
	REQUEST		*request = eap_session->request;
	VALUE_PAIR	*ki_vp, *version_vp;
	uint8_t		opc_buff[MILENAGE_OPC_SIZE];
	uint8_t	const	*opc_p;
	uint32_t	version;
	int		i;

	/*
	 *	Generate a new RAND value, and derive Kc and SRES from Ki
	 */
	ki_vp = fr_pair_find_by_da(vps, attr_sim_ki, TAG_ANY);
	if (!ki_vp) {
		RDEBUG3("No &control:%sfound, not generating triplets locally", attr_sim_ki->name);
		return 1;
	} else if (ki_vp->vp_length != MILENAGE_KI_SIZE) {
		REDEBUG("&control:%s has incorrect length, expected 16 bytes got %zu bytes",
			attr_sim_ki->name, ki_vp->vp_length);
		return -1;
	}

	/*
	 *	Check to see if have a Ki for the IMSI, this allows us to generate the rest
	 *	of the triplets.
	 */
	version_vp = fr_pair_find_by_da(vps, attr_sim_algo_version, TAG_ANY);
	if (!version_vp) {
		if (vector_opc_from_op(request, &opc_p, opc_buff, vps, ki_vp->vp_octets) < 0) return -1;
		version = opc_p ? 4 : 3;
	/*
	 *	Version we explicitly specified, see if we can find the prerequisite
	 *	attributes.
	 */
	} else {
		version = version_vp->vp_uint32;
		if (version == 4) {
			if (vector_opc_from_op(request, &opc_p, opc_buff, vps, ki_vp->vp_octets) < 0) return -1;
			if (!opc_p) {
				RPEDEBUG2("No &control:%s or &control:%s found, "
					  "can't run Milenage (COMP128-4)", attr_sim_op->name, attr_sim_opc->name);
				return -1;
			}
		}
	}

	for (i = 0; i < SIM_VECTOR_GSM_RAND_SIZE; i += sizeof(uint32_t)) {
		uint32_t rand = fr_rand();
		memcpy(&keys->gsm.vector[idx].rand[i], &rand, sizeof(rand));
	}

	switch (version) {
	case 1:
		comp128v1(keys->gsm.vector[idx].sres,
			  keys->gsm.vector[idx].kc,
			  ki_vp->vp_octets,
			  keys->gsm.vector[idx].rand);
		break;

	case 2:
		comp128v23(keys->gsm.vector[idx].sres,
			   keys->gsm.vector[idx].kc,
			   ki_vp->vp_octets,
			   keys->gsm.vector[idx].rand, true);
		break;

	case 3:
		comp128v23(keys->gsm.vector[idx].sres,
			   keys->gsm.vector[idx].kc,
			   ki_vp->vp_octets,
			   keys->gsm.vector[idx].rand, false);
		break;

	case 4:
		if (milenage_gsm_generate(keys->gsm.vector[idx].sres,
					  keys->gsm.vector[idx].kc,
					  opc_p,
					  ki_vp->vp_octets,
					  keys->gsm.vector[idx].rand) < 0) {
			RPEDEBUG2("Failed deriving GSM triplet");
			return -1;
		}
		return 0;

	default:
		REDEBUG("Unknown/unsupported algorithm %i", version);
		return -1;
	}
	return 0;
}
Ejemplo n.º 22
0
/*
 *	Send one packet.
 */
static int send_one_packet(rc_request_t *request)
{
	assert(request->done == false);

	/*
	 *	Remember when we have to wake up, to re-send the
	 *	request, of we didn't receive a reply.
	 */
	if ((sleep_time == -1) || (sleep_time > (int) timeout)) sleep_time = (int) timeout;

	/*
	 *	Haven't sent the packet yet.  Initialize it.
	 */
	if (request->packet->id == -1) {
		int i;
		bool rcode;

		assert(request->reply == NULL);

		/*
		 *	Didn't find a free packet ID, we're not done,
		 *	we don't sleep, and we stop trying to process
		 *	this packet.
		 */
	retry:
		request->packet->src_ipaddr.af = server_ipaddr.af;
		rcode = fr_packet_list_id_alloc(pl, ipproto, &request->packet, NULL);
		if (!rcode) {
			int mysockfd;

#ifdef WITH_TCP
			if (proto) {
				mysockfd = fr_socket_client_tcp(NULL,
								&request->packet->dst_ipaddr,
								request->packet->dst_port, false);
			} else
#endif
			mysockfd = fr_socket(&client_ipaddr, 0);
			if (mysockfd < 0) {
				ERROR("Failed opening socket");
				exit(1);
			}
			if (!fr_packet_list_socket_add(pl, mysockfd, ipproto,
						       &request->packet->dst_ipaddr,
						       request->packet->dst_port, NULL)) {
				ERROR("Can't add new socket");
				exit(1);
			}
			goto retry;
		}

		assert(request->packet->id != -1);
		assert(request->packet->data == NULL);

		for (i = 0; i < 4; i++) {
			((uint32_t *) request->packet->vector)[i] = fr_rand();
		}

		/*
		 *	Update the password, so it can be encrypted with the
		 *	new authentication vector.
		 */
		if (request->password) {
			VALUE_PAIR *vp;

			if ((vp = fr_pair_find_by_num(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) {
				fr_pair_value_strcpy(vp, request->password->vp_strvalue);

			} else if ((vp = fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) {
				uint8_t buffer[17];

				rad_chap_encode(request->packet, buffer, fr_rand() & 0xff, request->password);
				fr_pair_value_memcpy(vp, buffer, 17);

			} else if (fr_pair_find_by_num(request->packet->vps, PW_MS_CHAP_PASSWORD, 0, TAG_ANY) != NULL) {
				mschapv1_encode(request->packet, &request->packet->vps, request->password->vp_strvalue);

			} else {
				DEBUG("WARNING: No password in the request");
			}
		}

		request->timestamp = time(NULL);
		request->tries = 1;
		request->resend++;

	} else {		/* request->packet->id >= 0 */
		time_t now = time(NULL);

		/*
		 *	FIXME: Accounting packets are never retried!
		 *	The Acct-Delay-Time attribute is updated to
		 *	reflect the delay, and the packet is re-sent
		 *	from scratch!
		 */

		/*
		 *	Not time for a retry, do so.
		 */
		if ((now - request->timestamp) < timeout) {
			/*
			 *	When we walk over the tree sending
			 *	packets, we update the minimum time
			 *	required to sleep.
			 */
			if ((sleep_time == -1) ||
			    (sleep_time > (now - request->timestamp))) {
				sleep_time = now - request->timestamp;
			}
			return 0;
		}

		/*
		 *	We're not trying later, maybe the packet is done.
		 */
		if (request->tries == retries) {
			assert(request->packet->id >= 0);

			/*
			 *	Delete the request from the tree of
			 *	outstanding requests.
			 */
			fr_packet_list_yank(pl, request->packet);

			REDEBUG("No reply from server for ID %d socket %d",
				request->packet->id, request->packet->sockfd);
			deallocate_id(request);

			/*
			 *	Normally we mark it "done" when we've received
			 *	the reply, but this is a special case.
			 */
			if (request->resend == resend_count) {
				request->done = true;
			}
			stats.lost++;
			return -1;
		}

		/*
		 *	We are trying later.
		 */
		request->timestamp = now;
		request->tries++;
	}

	/*
	 *	Send the packet.
	 */
	if (rad_send(request->packet, NULL, secret) < 0) {
		REDEBUG("Failed to send packet for ID %d", request->packet->id);
		deallocate_id(request);
		request->done = true;
		return -1;
	}

	fr_packet_header_print(fr_log_fp, request->packet, false);
	if (fr_debug_lvl > 0) vp_printlist(fr_log_fp, request->packet->vps);

	return 0;
}
Ejemplo n.º 23
0
/*
 *	Send one packet.
 */
static int send_one_packet(radclient_t *radclient)
{
	assert(radclient->done == 0);

	/*
	 *	Remember when we have to wake up, to re-send the
	 *	request, of we didn't receive a response.
	 */
	if ((sleep_time == -1) ||
	    (sleep_time > (int) timeout)) {
		sleep_time = (int) timeout;
	}

	/*
	 *	Haven't sent the packet yet.  Initialize it.
	 */
	if (radclient->request->id == -1) {
		int i, rcode;

		assert(radclient->reply == NULL);

		/*
		 *	Didn't find a free packet ID, we're not done,
		 *	we don't sleep, and we stop trying to process
		 *	this packet.
		 */
	retry:
		radclient->request->src_ipaddr.af = server_ipaddr.af;
		rcode = fr_packet_list_id_alloc(pl, ipproto,
						radclient->request, NULL);
		if (rcode < 0) {
			int mysockfd;

#ifdef WITH_TCP
			if (proto) {
				mysockfd = fr_tcp_client_socket(NULL,
								&server_ipaddr,
								server_port);
			} else
#endif
			mysockfd = fr_socket(&client_ipaddr, 0);
			if (!mysockfd) {
				fprintf(stderr, "radclient: Can't open new socket\n");
				exit(1);
			}
			if (!fr_packet_list_socket_add(pl, mysockfd, ipproto,
						       &server_ipaddr,
						       server_port, NULL)) {
				fprintf(stderr, "radclient: Can't add new socket\n");
				exit(1);
			}
			goto retry;
		}

		if (rcode == 0) {
			done = 0;
			sleep_time = 0;
			return 0;
		}

		assert(radclient->request->id != -1);
		assert(radclient->request->data == NULL);

		for (i = 0; i < 4; i++) {
			((uint32_t *) radclient->request->vector)[i] = fr_rand();
		}

		/*
		 *	Update the password, so it can be encrypted with the
		 *	new authentication vector.
		 */
		if (radclient->password[0] != '\0') {
			VALUE_PAIR *vp;

			if ((vp = pairfind(radclient->request->vps, PW_USER_PASSWORD, 0)) != NULL) {
				strlcpy(vp->vp_strvalue, radclient->password,
					sizeof(vp->vp_strvalue));
				vp->length = strlen(vp->vp_strvalue);

			} else if ((vp = pairfind(radclient->request->vps, PW_CHAP_PASSWORD, 0)) != NULL) {
				int already_hex = 0;

				/*
				 *	If it's 17 octets, it *might* be already encoded.
				 *	Or, it might just be a 17-character password (maybe UTF-8)
				 *	Check it for non-printable characters.  The odds of ALL
				 *	of the characters being 32..255 is (1-7/8)^17, or (1/8)^17,
				 *	or 1/(2^51), which is pretty much zero.
				 */
				if (vp->length == 17) {
					for (i = 0; i < 17; i++) {
						if (vp->vp_octets[i] < 32) {
							already_hex = 1;
							break;
						}
					}
				}

				/*
				 *	Allow the user to specify ASCII or hex CHAP-Password
				 */
				if (!already_hex) {
					strlcpy(vp->vp_strvalue, radclient->password,
						sizeof(vp->vp_strvalue));
					vp->length = strlen(vp->vp_strvalue);
					
					rad_chap_encode(radclient->request,
							vp->vp_octets,
							fr_rand() & 0xff, vp);
					vp->length = 17;
				}
			} else if (pairfind(radclient->request->vps, PW_MSCHAP_PASSWORD, 0) != NULL) {
				mschapv1_encode(&radclient->request->vps,
						radclient->password);
			} else if (fr_debug_flag) {
				printf("WARNING: No password in the request\n");
			}
		}

		radclient->timestamp = time(NULL);
		radclient->tries = 1;
		radclient->resend++;

		/*
		 *	Duplicate found.  Serious error!
		 */
		if (!fr_packet_list_insert(pl, &radclient->request)) {
			assert(0 == 1);
		}

#ifdef WITH_TCP
		/*
		 *	WTF?
		 */
		if (client_port == 0) {
			client_ipaddr = radclient->request->src_ipaddr;
			client_port = radclient->request->src_port;
		}
#endif

	} else {		/* radclient->request->id >= 0 */
		time_t now = time(NULL);

		/*
		 *	FIXME: Accounting packets are never retried!
		 *	The Acct-Delay-Time attribute is updated to
		 *	reflect the delay, and the packet is re-sent
		 *	from scratch!
		 */

		/*
		 *	Not time for a retry, do so.
		 */
		if ((now - radclient->timestamp) < timeout) {
			/*
			 *	When we walk over the tree sending
			 *	packets, we update the minimum time
			 *	required to sleep.
			 */
			if ((sleep_time == -1) ||
			    (sleep_time > (now - radclient->timestamp))) {
				sleep_time = now - radclient->timestamp;
			}
			return 0;
		}

		/*
		 *	We're not trying later, maybe the packet is done.
		 */
		if (radclient->tries == retries) {
			assert(radclient->request->id >= 0);

			/*
			 *	Delete the request from the tree of
			 *	outstanding requests.
			 */
			fr_packet_list_yank(pl, radclient->request);

			fprintf(stderr, "radclient: no response from server for ID %d socket %d\n", radclient->request->id, radclient->request->sockfd);
			deallocate_id(radclient);

			/*
			 *	Normally we mark it "done" when we've received
			 *	the response, but this is a special case.
			 */
			if (radclient->resend == resend_count) {
				radclient->done = 1;
			}
			totallost++;
			return -1;
		}

		/*
		 *	We are trying later.
		 */
		radclient->timestamp = now;
		radclient->tries++;
	}


	/*
	 *	Send the packet.
	 */
	if (rad_send(radclient->request, NULL, secret) < 0) {
		fprintf(stderr, "radclient: Failed to send packet for ID %d: %s\n",
			radclient->request->id, fr_strerror());
	}

	if (fr_debug_flag > 2) print_hex(radclient->request);

	return 0;
}
Ejemplo n.º 24
0
/*
 * read the config section and load all the eap authentication types present.
 */
static int eap_instantiate(CONF_SECTION *cs, void **instance)
{
	int i, num_types;
	int		has_tls, do_tls;
	rlm_eap_t	*inst;
	CONF_SECTION	*scs;

	inst = (rlm_eap_t *) malloc(sizeof(*inst));
	if (!inst) {
		return -1;
	}
	memset(inst, 0, sizeof(*inst));
	if (cf_section_parse(cs, inst, module_config) < 0) {
		eap_detach(inst);
		return -1;
	}

	/*
	 *	Create our own random pool.
	 */
	for (i = 0; i < 256; i++) {
		inst->rand_pool.randrsl[i] = fr_rand();
	}
	fr_randinit(&inst->rand_pool, 1);

	/*
	 *	List of sessions are set to NULL by the memset
	 *	of 'inst', above.
	 */

	/*
	 *	Lookup sessions in the tree.  We don't free them in
	 *	the tree, as that's taken care of elsewhere...
	 */
	inst->session_tree = rbtree_create(eap_handler_cmp, NULL, 0);
	if (!inst->session_tree) {
		radlog(L_ERR|L_CONS, "rlm_eap2: Cannot initialize tree");
		eap_detach(inst);
		return -1;
	}

	/*
	 *	This registers ALL available methods.
	 *
	 *	FIXME: we probably want to selectively register
	 *	some methods.
	 */
	if (eap_server_register_methods() < 0) {
		eap_detach(inst);
		return -1;
	}

	/* Load all the configured EAP-Types */
	num_types = 0;
	has_tls = do_tls = 0;
	for (scs=cf_subsection_find_next(cs, NULL, NULL);
		scs != NULL;
		scs=cf_subsection_find_next(cs, scs, NULL)) {
		const char	*auth_type;
		char		buffer[64], *p;

		auth_type = cf_section_name1(scs);

		if (!auth_type)  continue;

		if (num_types >= EAP_MAX_METHODS) {
			radlog(L_INFO, "WARNING: Ignoring EAP type %s: too many types defined", auth_type);
			continue;
		}

		/*
		 *	Hostapd doesn't do case-insensitive comparisons.
		 *	So we mash everything to uppercase for it.
		 */
		strlcpy(buffer, auth_type, sizeof(buffer));

		for (p = buffer; *p; p++) {
			if (!islower((int)*p)) continue;
			*p = toupper((int)*p);
		}

		inst->methods[num_types] = eap_server_get_type(buffer,
							       &inst->vendors[num_types]);
		if (inst->methods[num_types] == EAP_TYPE_NONE) {
			radlog(L_ERR|L_CONS, "rlm_eap2: Unknown EAP type %s",
			       auth_type);
			eap_detach(inst);
			return -1;
		}

		switch (inst->methods[num_types]) {
		case EAP_TYPE_TLS:
			has_tls = TRUE;
			/* FALL-THROUGH */

		case EAP_TYPE_TTLS:
		case EAP_TYPE_PEAP:
		case EAP_TYPE_FAST:
			do_tls = TRUE;
			break;

		default:
			break;
		}

		num_types++;	/* successfully loaded one more types */
	}
	inst->num_types = num_types;

	if (do_tls && !has_tls) {
		radlog(L_ERR|L_CONS, "rlm_eap2: TLS has not been configured.  Cannot do methods that need TLS.");
		eap_detach(inst);
		return -1;
	}

	if (do_tls) {
		/*
		 *	Initialize TLS.
		 */
		if (eap_example_server_init_tls(inst) < 0) {
			radlog(L_ERR|L_CONS, "rlm_eap2: Cannot initialize TLS");
			eap_detach(inst);
			return -1;
		}
	}

	pthread_mutex_init(&(inst->session_mutex), NULL);

	*instance = inst;
	return 0;
}
Ejemplo n.º 25
0
/*
 * read the config section and load all the eap authentication types present.
 */
static int mod_instantiate(CONF_SECTION *cs, void *instance)
{
	int		i, ret;
	eap_type_t	method;
	int		num_methods;
	CONF_SECTION 	*scs;
	rlm_eap_t	*inst = instance;

	/*
	 *	Create our own random pool.
	 */
	for (i = 0; i < 256; i++) {
		inst->rand_pool.randrsl[i] = fr_rand();
	}
	fr_randinit(&inst->rand_pool, 1);
	inst->rand_pool.randcnt = 0;

	inst->xlat_name = cf_section_name2(cs);
	if (!inst->xlat_name) inst->xlat_name = "EAP";

	/* Load all the configured EAP-Types */
	num_methods = 0;
	for(scs = cf_subsection_find_next(cs, NULL, NULL);
	    scs != NULL;
	    scs = cf_subsection_find_next(cs, scs, NULL)) {

		const char *name;

		name = cf_section_name1(scs);
		if (!name)  continue;

		if (!strcmp(name, TLS_CONFIG_SECTION))  continue;

		method = eap_name2type(name);
		if (method == PW_EAP_INVALID) {
			cf_log_err_cs(cs, "Unknown EAP method %s", name);
			return -1;
		}
		
		if ((method < PW_EAP_MD5) || (method >= PW_EAP_MAX_TYPES)) {
			cf_log_err_cs(cs, "Invalid EAP method %s (unsupported)", name);
			return -1;
		}

#if !defined(HAVE_OPENSSL_SSL_H) || !defined(HAVE_LIBSSL)
		/*
		 *	This allows the default configuration to be
		 *	shipped with EAP-TLS, etc. enabled.  If the
		 *	system doesn't have OpenSSL, they will be
		 *	ignored.
		 *
		 *	If the system does have OpenSSL, then this
		 *	code will not be used.  The administrator will
		 *	then have to delete the tls,
		 *	etc. configurations from eap.conf in order to
		 *	have EAP without the TLS types.
		 */
		if ((method == PW_EAP_TLS) ||
		    (method == PW_EAP_TTLS) ||
		    (method == PW_EAP_PEAP)) {
			DEBUG2("rlm_eap (%s): Ignoring EAP method %s because we do not have OpenSSL support",
			       inst->xlat_name, name);
			continue;
		}
#endif

		/*
		 *	Load the type.
		 */
		ret = eap_module_load(inst, &inst->methods[method], method, scs);
		
		(void) talloc_get_type_abort(inst->methods[method], eap_module_t);
		
		if (ret < 0) {
			(void) talloc_steal(inst, inst->methods[method]);
			return -1;
		}

		(void) talloc_steal(inst, inst->methods[method]);
		num_methods++;	/* successfully loaded one more methods */
	}

	if (num_methods == 0) {
		cf_log_err_cs(cs, "No EAP method configured, module cannot do anything");
		return -1;
	}

	/*
	 *	Ensure that the default EAP type is loaded.
	 */
	method = eap_name2type(inst->default_method_name);
	if (method == PW_EAP_INVALID) {
		cf_log_err_cs(cs, "Unknown default EAP method '%s'",
		       inst->default_method_name);
		return -1;
	}

	if (!inst->methods[method]) {
		cf_log_err_cs(cs, "No such sub-type for default EAP method %s",
		       inst->default_method_name);
		return -1;
	}
	inst->default_method = method; /* save the numerical method */

	/*
	 *	List of sessions are set to NULL by the memset
	 *	of 'inst', above.
	 */

	/*
	 *	Lookup sessions in the tree.  We don't free them in
	 *	the tree, as that's taken care of elsewhere...
	 */
	inst->session_tree = rbtree_create(eap_handler_cmp, NULL, 0);
	if (!inst->session_tree) {
		radlog(L_ERR, "rlm_eap (%s): Cannot initialize tree", inst->xlat_name);
		return -1;
	}

	if (fr_debug_flag) {
		inst->handler_tree = rbtree_create(eap_handler_ptr_cmp, NULL, 0);
		if (!inst->handler_tree) {
			radlog(L_ERR, "rlm_eap (%s): Cannot initialize tree", inst->xlat_name);
			return -1;
		}

#ifdef HAVE_PTHREAD_H
		if (pthread_mutex_init(&(inst->handler_mutex), NULL) < 0) {
			radlog(L_ERR, "rlm_eap (%s): Failed initializing mutex: %s", inst->xlat_name, strerror(errno));
			return -1;
		}
#endif
	}

#ifdef HAVE_PTHREAD_H
	if (pthread_mutex_init(&(inst->session_mutex), NULL) < 0) {
		radlog(L_ERR, "rlm_eap (%s): Failed initializing mutex: %s", inst->xlat_name, strerror(errno));
		return -1;
	}
#endif

	return 0;
}
Ejemplo n.º 26
0
/*
 * read the config section and load all the eap authentication types present.
 */
static int eap_instantiate(CONF_SECTION *cs, void **instance)
{
	int		i, eap_type;
	int		num_types;
	CONF_SECTION 	*scs;
	rlm_eap_t	*inst;

	inst = (rlm_eap_t *) malloc(sizeof(*inst));
	if (!inst) {
		return -1;
	}
	memset(inst, 0, sizeof(*inst));
	if (cf_section_parse(cs, inst, module_config) < 0) {
		eap_detach(inst);
		return -1;
	}

	/*
	 *	Create our own random pool.
	 */
	for (i = 0; i < 256; i++) {
		inst->rand_pool.randrsl[i] = fr_rand();
	}
	fr_randinit(&inst->rand_pool, 1);
	inst->rand_pool.randcnt = 0;

	inst->xlat_name = cf_section_name2(cs);
	if (!inst->xlat_name) inst->xlat_name = "EAP";

	/* Load all the configured EAP-Types */
	num_types = 0;
	for(scs=cf_subsection_find_next(cs, NULL, NULL);
		scs != NULL;
		scs=cf_subsection_find_next(cs, scs, NULL)) {

		const char	*auth_type;

		auth_type = cf_section_name1(scs);

		if (!auth_type)  continue;

		if (!strcmp(auth_type, TLS_CONFIG_SECTION))  continue;

		eap_type = eaptype_name2type(auth_type);
		if (eap_type < 0) {
			radlog(L_ERR, "rlm_eap: Unknown EAP type %s",
			       auth_type);
			eap_detach(inst);
			return -1;
		}

#ifndef HAVE_OPENSSL_SSL_H
		/*
		 *	This allows the default configuration to be
		 *	shipped with EAP-TLS, etc. enabled.  If the
		 *	system doesn't have OpenSSL, they will be
		 *	ignored.
		 *
		 *	If the system does have OpenSSL, then this
		 *	code will not be used.  The administrator will
		 *	then have to delete the tls,
		 *	etc. configurations from eap.conf in order to
		 *	have EAP without the TLS types.
		 */
		if ((eap_type == PW_EAP_TLS) ||
		    (eap_type == PW_EAP_TTLS) ||
		    (eap_type == PW_EAP_PEAP)) {
			DEBUG2("Ignoring EAP-Type/%s because we do not have OpenSSL support.", auth_type);
			continue;
		}
#endif

		/*
		 *	Load the type.
		 */
		if (eaptype_load(&inst->types[eap_type], eap_type, scs) < 0) {
			eap_detach(inst);
			return -1;
		}

		num_types++;	/* successfully loaded one more types */
	}

	if (num_types == 0) {
		radlog(L_ERR|L_CONS, "rlm_eap: No EAP type configured, module cannot do anything.");
		eap_detach(inst);
		return -1;
	}

	/*
	 *	Ensure that the default EAP type is loaded.
	 */
	eap_type = eaptype_name2type(inst->default_eap_type_name);
	if (eap_type < 0) {
		radlog(L_ERR|L_CONS, "rlm_eap: Unknown default EAP type %s",
		       inst->default_eap_type_name);
		eap_detach(inst);
		return -1;
	}

	if (inst->types[eap_type] == NULL) {
		radlog(L_ERR|L_CONS, "rlm_eap: No such sub-type for default EAP type %s",
		       inst->default_eap_type_name);
		eap_detach(inst);
		return -1;
	}
	inst->default_eap_type = eap_type; /* save the numerical type */

	/*
	 *	List of sessions are set to NULL by the memset
	 *	of 'inst', above.
	 */

	/*
	 *	Lookup sessions in the tree.  We don't free them in
	 *	the tree, as that's taken care of elsewhere...
	 */
	inst->session_tree = rbtree_create(eap_handler_cmp, NULL, 0);
	if (!inst->session_tree) {
		radlog(L_ERR|L_CONS, "rlm_eap: Cannot initialize tree");
		eap_detach(inst);
		return -1;
	}

	if (fr_debug_flag) {
		inst->handler_tree = rbtree_create(eap_handler_ptr_cmp, NULL, 0);
		if (!inst->handler_tree) {
			radlog(L_ERR|L_CONS, "rlm_eap: Cannot initialize tree");
			eap_detach(inst);
			return -1;
		}

#ifdef HAVE_PTHREAD_H
		if (pthread_mutex_init(&(inst->handler_mutex), NULL) < 0) {
			radlog(L_ERR|L_CONS, "rlm_eap: Failed initializing mutex: %s", strerror(errno));
			eap_detach(inst);
			return -1;
		}
#endif
	}

#ifdef HAVE_PTHREAD_H
	if (pthread_mutex_init(&(inst->session_mutex), NULL) < 0) {
		radlog(L_ERR|L_CONS, "rlm_eap: Failed initializing mutex: %s", strerror(errno));
		eap_detach(inst);
		return -1;
	}
#endif

	*instance = inst;
	return 0;
}
Ejemplo n.º 27
0
static REQUEST *request_setup(FILE *fp)
{
	VALUE_PAIR *vp;
	REQUEST *request;
	vp_cursor_t cursor;

	/*
	 *	Create and initialize the new request.
	 */
	request = request_alloc(NULL);

	request->packet = rad_alloc(request, false);
	if (!request->packet) {
		ERROR("No memory");
		talloc_free(request);
		return NULL;
	}

	request->reply = rad_alloc(request, false);
	if (!request->reply) {
		ERROR("No memory");
		talloc_free(request);
		return NULL;
	}

	request->listener = listen_alloc(request);
	request->client = client_alloc(request);

	request->number = 0;

	request->master_state = REQUEST_ACTIVE;
	request->child_state = REQUEST_RUNNING;
	request->handle = NULL;
	request->server = talloc_typed_strdup(request, "default");

	request->root = &main_config;

	/*
	 *	Read packet from fp
	 */
	if (readvp2(request->packet, &request->packet->vps, fp, &filedone) < 0) {
		fr_perror("unittest");
		talloc_free(request);
		return NULL;
	}

	/*
	 *	Set the defaults for IPs, etc.
	 */
	request->packet->code = PW_CODE_ACCESS_REQUEST;

	request->packet->src_ipaddr.af = AF_INET;
	request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK);
	request->packet->src_port = 18120;

	request->packet->dst_ipaddr.af = AF_INET;
	request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK);
	request->packet->dst_port = 1812;

	/*
	 *	Copied from radclient
	 */
#if 1
	/*
	 *	Fix up Digest-Attributes issues
	 */
	for (vp = fr_cursor_init(&cursor, &request->packet->vps);
	     vp;
	     vp = fr_cursor_next(&cursor)) {
		/*
		 *	Double quoted strings get marked up as xlat expansions,
		 *	but we don't support that here.
		 */
		if (vp->type == VT_XLAT) {
			vp->vp_strvalue = vp->value.xlat;
			vp->value.xlat = NULL;
			vp->type = VT_DATA;
		}

		if (!vp->da->vendor) switch (vp->da->attr) {
		default:
			break;

			/*
			 *	Allow it to set the packet type in
			 *	the attributes read from the file.
			 */
		case PW_PACKET_TYPE:
			request->packet->code = vp->vp_integer;
			break;

		case PW_PACKET_DST_PORT:
			request->packet->dst_port = (vp->vp_integer & 0xffff);
			break;

		case PW_PACKET_DST_IP_ADDRESS:
			request->packet->dst_ipaddr.af = AF_INET;
			request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
			break;

		case PW_PACKET_DST_IPV6_ADDRESS:
			request->packet->dst_ipaddr.af = AF_INET6;
			request->packet->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
			break;

		case PW_PACKET_SRC_PORT:
			request->packet->src_port = (vp->vp_integer & 0xffff);
			break;

		case PW_PACKET_SRC_IP_ADDRESS:
			request->packet->src_ipaddr.af = AF_INET;
			request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
			break;

		case PW_PACKET_SRC_IPV6_ADDRESS:
			request->packet->src_ipaddr.af = AF_INET6;
			request->packet->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
			break;

		case PW_CHAP_PASSWORD: {
			int i, already_hex = 0;

			/*
			 *	If it's 17 octets, it *might* be already encoded.
			 *	Or, it might just be a 17-character password (maybe UTF-8)
			 *	Check it for non-printable characters.  The odds of ALL
			 *	of the characters being 32..255 is (1-7/8)^17, or (1/8)^17,
			 *	or 1/(2^51), which is pretty much zero.
			 */
			if (vp->length == 17) {
				for (i = 0; i < 17; i++) {
					if (vp->vp_octets[i] < 32) {
						already_hex = 1;
						break;
					}
				}
			}

			/*
			 *	Allow the user to specify ASCII or hex CHAP-Password
			 */
			if (!already_hex) {
				uint8_t *p;
				size_t len, len2;

				len = len2 = vp->length;
				if (len2 < 17) len2 = 17;

				p = talloc_zero_array(vp, uint8_t, len2);

				memcpy(p, vp->vp_strvalue, len);

				rad_chap_encode(request->packet,
						p,
						fr_rand() & 0xff, vp);
				vp->vp_octets = p;
				vp->length = 17;
			}
		}
			break;

		case PW_DIGEST_REALM:
		case PW_DIGEST_NONCE:
		case PW_DIGEST_METHOD:
		case PW_DIGEST_URI:
		case PW_DIGEST_QOP:
		case PW_DIGEST_ALGORITHM:
		case PW_DIGEST_BODY_DIGEST:
		case PW_DIGEST_CNONCE:
		case PW_DIGEST_NONCE_COUNT:
		case PW_DIGEST_USER_NAME:
			/* overlapping! */
		{
			DICT_ATTR const *da;
			uint8_t *p, *q;

			p = talloc_array(vp, uint8_t, vp->length + 2);

			memcpy(p + 2, vp->vp_octets, vp->length);
			p[0] = vp->da->attr - PW_DIGEST_REALM + 1;
			vp->length += 2;
			p[1] = vp->length;

			da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0);
			rad_assert(da != NULL);
			vp->da = da;

			/*
			 *	Re-do pairmemsteal ourselves,
			 *	because we play games with
			 *	vp->da, and pairmemsteal goes
			 *	to GREAT lengths to sanitize
			 *	and fix and change and
			 *	double-check the various
			 *	fields.
			 */
			memcpy(&q, &vp->vp_octets, sizeof(q));
			talloc_free(q);

			vp->vp_octets = talloc_steal(vp, p);
			vp->type = VT_DATA;

			VERIFY_VP(vp);
		}

		break;
		}
	} /* loop over the VP's we read in */
#endif

	if (debug_flag) {
		for (vp = fr_cursor_init(&cursor, &request->packet->vps);
		     vp;
		     vp = fr_cursor_next(&cursor)) {
			/*
			 *	Take this opportunity to verify all the VALUE_PAIRs are still valid.
			 */
			if (!talloc_get_type(vp, VALUE_PAIR)) {
				ERROR("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp));

				fr_log_talloc_report(vp);
				rad_assert(0);
			}

			vp_print(fr_log_fp, vp);
		}
		fflush(fr_log_fp);
	}

	/*
	 *	FIXME: set IPs, etc.
	 */
	request->packet->code = PW_CODE_ACCESS_REQUEST;

	request->packet->src_ipaddr.af = AF_INET;
	request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK);
	request->packet->src_port = 18120;

	request->packet->dst_ipaddr.af = AF_INET;
	request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK);
	request->packet->dst_port = 1812;

	/*
	 *	Build the reply template from the request.
	 */
	request->reply->sockfd = request->packet->sockfd;
	request->reply->dst_ipaddr = request->packet->src_ipaddr;
	request->reply->src_ipaddr = request->packet->dst_ipaddr;
	request->reply->dst_port = request->packet->src_port;
	request->reply->src_port = request->packet->dst_port;
	request->reply->id = request->packet->id;
	request->reply->code = 0; /* UNKNOWN code */
	memcpy(request->reply->vector, request->packet->vector,
	       sizeof(request->reply->vector));
	request->reply->vps = NULL;
	request->reply->data = NULL;
	request->reply->data_len = 0;

	/*
	 *	Debugging
	 */
	request->log.lvl = debug_flag;
	request->log.func = vradlog_request;

	request->username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
	request->password = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);

	return request;
}
Ejemplo n.º 28
0
/*
 *	Initiate the EAP-MD5 session by sending a challenge to the peer.
 */
static int mod_session_init(UNUSED void *instance, eap_handler_t *handler)
{
	int		i;
	MD5_PACKET	*reply;
	REQUEST		*request = handler->request;

	/*
	 *	Allocate an EAP-MD5 packet.
	 */
	reply = talloc(handler, MD5_PACKET);
	if (!reply)  {
		return 0;
	}

	/*
	 *	Fill it with data.
	 */
	reply->code = PW_MD5_CHALLENGE;
	reply->length = 1 + MD5_CHALLENGE_LEN; /* one byte of value size */
	reply->value_size = MD5_CHALLENGE_LEN;

	/*
	 *	Allocate user data.
	 */
	reply->value = talloc_array(reply, uint8_t, reply->value_size);
	if (!reply->value) {
		talloc_free(reply);
		return 0;
	}

	/*
	 *	Get a random challenge.
	 */
	for (i = 0; i < reply->value_size; i++) {
		reply->value[i] = fr_rand();
	}
	RDEBUG2("Issuing MD5 Challenge");

	/*
	 *	Keep track of the challenge.
	 */
	handler->opaque = talloc_array(handler, uint8_t, reply->value_size);
	rad_assert(handler->opaque != NULL);
	memcpy(handler->opaque, reply->value, reply->value_size);
	handler->free_opaque = NULL;

	/*
	 *	Compose the EAP-MD5 packet out of the data structure,
	 *	and free it.
	 */
	eapmd5_compose(handler->eap_ds, reply);

	/*
	 *	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 = PROCESS;

	return 1;
}
Ejemplo n.º 29
0
/** Generate a string of random chars
 *
 *  Build strings of random chars, useful for generating tokens and passcodes
 *  Format similar to String::Random.
 */
static ssize_t randstr_xlat(UNUSED void *instance, UNUSED REQUEST *request,
			    char const *fmt, char *out, size_t outlen)
{
	char const 	*p;
	unsigned int	result;
	size_t		freespace = outlen;

	if (outlen <= 1) return 0;

	*out = '\0';

	p = fmt;
	while (*p && (--freespace > 0)) {
		result = fr_rand();
		switch (*p) {
		/*
		 *  Lowercase letters
		 */
		case 'c':
			*out++ = 'a' + (result % 26);
			break;

		/*
		 *  Uppercase letters
		 */
		case 'C':
			*out++ = 'A' + (result % 26);
			break;

		/*
		 *  Numbers
		 */
		case 'n':
			*out++ = '0' + (result % 10);
			break;

		/*
		 *  Alpha numeric
		 */
		case 'a':
			*out++ = randstr_salt[result % (sizeof(randstr_salt) - 3)];
			break;

		/*
		 *  Punctuation
		 */
		case '!':
			*out++ = randstr_punc[result % (sizeof(randstr_punc) - 1)];
			break;

		/*
		 *  Alpa numeric + punctuation
		 */
		case '.':
			*out++ = '!' + (result % 95);
			break;

		/*
		 *  Alpha numeric + salt chars './'
		 */
		case 's':
			*out++ = randstr_salt[result % (sizeof(randstr_salt) - 1)];
			break;

		/*
		 *  Chars suitable for One Time Password tokens.
		 *  Alpha numeric with easily confused char pairs removed.
		 */
		case 'o':
			*out++ = randstr_otp[result % (sizeof(randstr_otp) - 1)];
			break;

		/*
		 *  Binary data as hexits (we don't really support
		 *  non printable chars).
		 */
		case 'h':
			if (freespace < 2) {
				break;
			}

			snprintf(out, 3, "%02x", result % 256);

			/* Already decremented */
			freespace -= 1;
			out += 2;
			break;

		/*
		 *  Binary data with uppercase hexits
		 */
		case 'H':
			if (freespace < 2) {
				break;
			}

			snprintf(out, 3, "%02X", result % 256);

			/* Already decremented */
			freespace -= 1;
			out += 2;
			break;

		default:
			ERROR("rlm_expr: invalid character class '%c'", *p);

			return -1;
		}

		p++;
	}

	*out++ = '\0';

	return outlen - freespace;
}
Ejemplo n.º 30
0
/** Copy packet to multiple servers
 *
 * Create a duplicate of the packet and send it to a list of realms
 * defined by the presence of the Replicate-To-Realm VP in the control
 * list of the current request.
 *
 * This is pretty hacky and is 100% fire and forget. If you're looking
 * to forward authentication requests to multiple realms and process
 * the responses, this function will not allow you to do that.
 *
 * @param[in] instance 	of this module.
 * @param[in] request 	The current request.
 * @param[in] list	of attributes to copy to the duplicate packet.
 * @param[in] code	to write into the code field of the duplicate packet.
 * @return RCODE fail on error, invalid if list does not exist, noop if no
 * 	   replications succeeded, else ok.
 */
static int replicate_packet(UNUSED void *instance, REQUEST *request,
			    pair_lists_t list, unsigned int code)
{
	int rcode = RLM_MODULE_NOOP;
	VALUE_PAIR *vp, **vps, *last;
	home_server *home;
	REALM *realm;
	home_pool_t *pool;
	RADIUS_PACKET *packet = NULL;

	last = request->config_items;

	/*
	 *	Send as many packets as necessary to different
	 *	destinations.
	 */
	while (1) {
		vp = pairfind(last, PW_REPLICATE_TO_REALM, 0, TAG_ANY);
		if (!vp) break;

		last = vp->next;

		realm = realm_find2(vp->vp_strvalue);
		if (!realm) {
			RDEBUG2E("Cannot Replicate to unknown realm %s", realm);
			continue;
		}
		
		/*
		 *	We shouldn't really do this on every loop.
		 */
		switch (request->packet->code) {
		default:
			RDEBUG2E("Cannot replicate unknown packet code %d",
				request->packet->code);
			cleanup(packet);
			return RLM_MODULE_FAIL;
		
		case PW_AUTHENTICATION_REQUEST:
			pool = realm->auth_pool;
			break;
			
#ifdef WITH_ACCOUNTING
			
		case PW_ACCOUNTING_REQUEST:
			pool = realm->acct_pool;
			break;
#endif
			
#ifdef WITH_COA
		case PW_COA_REQUEST:
		case PW_DISCONNECT_REQUEST:
			pool = realm->acct_pool;
			break;
#endif
		}
		
		if (!pool) {
			RDEBUG2W("Cancelling replication to Realm %s, as the realm is local.", realm->name);
			continue;
		}
		
		home = home_server_ldb(realm->name, pool, request);
		if (!home) {
			RDEBUG2E("Failed to find live home server for realm %s",
				realm->name);
			continue;
		}
		
		/*
		 *	For replication to multiple servers we re-use the packet
		 *	we built here.
		 */
		if (!packet) {
			packet = rad_alloc(NULL, 1);
			if (!packet) return RLM_MODULE_FAIL;
			packet->sockfd = -1;
			packet->code = code;
			packet->id = fr_rand() & 0xff;

			packet->sockfd = fr_socket(&home->src_ipaddr, 0);
			if (packet->sockfd < 0) {
				RDEBUGE("Failed opening socket: %s", fr_strerror());
				rcode = RLM_MODULE_FAIL;
				goto done;
			}
			
			vps = radius_list(request, list);
			if (!vps) {
				RDEBUGW("List '%s' doesn't exist for "
				       "this packet", fr_int2str(pair_lists,
				       list, "?unknown?"));
				rcode = RLM_MODULE_INVALID;
				goto done;
			}
			
			/*
			 *	Don't assume the list actually contains any
			 *	attributes.
			 */
			if (*vps) {
				packet->vps = paircopy(packet, *vps);
				if (!packet->vps) {
					rcode = RLM_MODULE_FAIL;
					goto done;
				}
			}
			


			/*
			 *	For CHAP, create the CHAP-Challenge if
			 *	it doesn't exist.
			 */
			if ((code == PW_AUTHENTICATION_REQUEST) &&
			    (pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY) != NULL) &&
			    (pairfind(request->packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY) == NULL)) {
				vp = radius_paircreate(request, &packet->vps,
						       PW_CHAP_CHALLENGE, 0);
				vp->length = AUTH_VECTOR_LEN;
				memcpy(vp->vp_strvalue, request->packet->vector,
				       AUTH_VECTOR_LEN);
			}
		} else {
			size_t i;

			for (i = 0; i < sizeof(packet->vector); i++) {
				packet->vector[i] = fr_rand() & 0xff;
			}

			packet->id++;
			free(packet->data);
			packet->data = NULL;
			packet->data_len = 0;
		}

		/*
		 *	(Re)-Write these.
		 */
		packet->dst_ipaddr = home->ipaddr;
		packet->dst_port = home->port;
		memset(&packet->src_ipaddr, 0, sizeof(packet->src_ipaddr));
		packet->src_port = 0;
		
		/*
		 *	Encode, sign and then send the packet.
		 */
		RDEBUG("Replicating list '%s' to Realm '%s'",
		       fr_int2str(pair_lists, list, "¿unknown?"),realm->name);
		if (rad_send(packet, NULL, home->secret) < 0) {
			RDEBUGE("Failed replicating packet: %s",
			       fr_strerror());
			rcode = RLM_MODULE_FAIL;
			goto done;
		}

		/*
		 *	We've sent it to at least one destination.
		 */
		rcode = RLM_MODULE_OK;
	}
	
	done:
	
	cleanup(packet);
	return rcode;
}