Ejemplo n.º 1
0
/*
 *	If we're proxying EAP, then there may be magic we need
 *	to do.
 */
static rlm_rcode_t mod_post_proxy(void *inst, REQUEST *request)
{
	size_t		i;
	size_t		len;
	VALUE_PAIR	*vp;
	eap_handler_t	*handler;

	/*
	 *	Just in case the admin lists EAP in post-proxy-type Fail.
	 */
	if (!request->proxy_reply) return RLM_MODULE_NOOP;

	/*
	 *	If there was a handler associated with this request,
	 *	then it's a tunneled request which was proxied...
	 */
	handler = request_data_get(request, inst, REQUEST_DATA_eap_handler_t);
	if (handler != NULL) {
		rlm_rcode_t rcode;
		eap_tunnel_data_t *data;

		/*
		 *	Grab the tunnel callbacks from the request.
		 */
		data = (eap_tunnel_data_t *) request_data_get(request,
							      request->proxy,
							      REQUEST_DATA_EAP_TUNNEL_CALLBACK);
		if (!data) {
			radlog_request(L_ERR, 0, request, "Failed to retrieve callback for tunneled session!");
			eap_handler_free(inst, handler);
			return RLM_MODULE_FAIL;
		}

		/*
		 *	Do the callback...
		 */
		RDEBUG2("Doing post-proxy callback");
		rcode = data->callback(handler, data->tls_session);
		free(data);
		if (rcode == 0) {
			RDEBUG2("Failed in post-proxy callback");
			eap_fail(handler);
			eap_handler_free(inst, handler);
			return RLM_MODULE_REJECT;
		}

		/*
		 *	We are done, wrap the EAP-request in RADIUS to send
		 *	with all other required radius attributes
		 */
		eap_compose(handler);

		/*
		 *	Add to the list only if it is EAP-Request, OR if
		 *	it's LEAP, and a response.
		 */
		if ((handler->eap_ds->request->code == PW_EAP_REQUEST) &&
		    (handler->eap_ds->request->type.num >= PW_EAP_MD5)) {
			if (!eaplist_add(inst, handler)) {
				eap_fail(handler);
				eap_handler_free(inst, handler);
				return RLM_MODULE_FAIL;
			}
			
		} else {	/* couldn't have been LEAP, there's no tunnel */
			RDEBUG2("Freeing handler");
			/* handler is not required any more, free it now */
			eap_handler_free(inst, handler);
		}

		/*
		 *	If it's an Access-Accept, RFC 2869, Section 2.3.1
		 *	says that we MUST include a User-Name attribute in the
		 *	Access-Accept.
		 */
		if ((request->reply->code == PW_AUTHENTICATION_ACK) &&
		    request->username) {
			/*
			 *	Doesn't exist, add it in.
			 */
			vp = pairfind(request->reply->vps, PW_USER_NAME, 0, TAG_ANY);
			if (!vp) {
				pairmake_reply("User-Name",
					       request->username->vp_strvalue,
					       T_OP_EQ);
			}
		}

		return RLM_MODULE_OK;
	} else {
		RDEBUG2("No pre-existing handler found");
	}

	/*
	 *	There may be more than one Cisco-AVPair.
	 *	Ensure we find the one with the LEAP attribute.
	 */
	vp = request->proxy_reply->vps;
	for (;;) {
		/*
		 *	Hmm... there's got to be a better way to
		 *	discover codes for vendor attributes.
		 *
		 *	This is vendor Cisco (9), Cisco-AVPair
		 *	attribute (1)
		 */
		vp = pairfind(vp, 1, 9, TAG_ANY);
		if (!vp) {
			return RLM_MODULE_NOOP;
		}

		/*
		 *	If it's "leap:session-key", then stop.
		 *
		 *	The format is VERY specific!
		 */
		if (strncasecmp(vp->vp_strvalue, "leap:session-key=", 17) == 0) {
			break;
		}

		/*
		 *	Not this AV-pair.  Go to the next one.
		 */
		vp = vp->next;
	}

	/*
	 *	The format is very specific.
	 */
	if (vp->length != 17 + 34) {
		RDEBUG2("Cisco-AVPair with leap:session-key has incorrect length %d: Expected %d",
		       vp->length, 17 + 34);
		return RLM_MODULE_NOOP;
	}

	/*
	 *	Decrypt the session key, using the proxy data.
	 */
	i = 34;			/* starts off with 34 octets */
	len = rad_tunnel_pwdecode(vp->vp_octets + 17, &i,
				  request->home_server->secret,
				  request->proxy->vector);

	/*
	 *	FIXME: Assert that i == 16.
	 */

	/*
	 *	Encrypt the session key again, using the request data.
	 */
	rad_tunnel_pwencode(vp->vp_strvalue + 17, &len,
			    request->client->secret,
			    request->packet->vector);

	return RLM_MODULE_UPDATED;
}
Ejemplo n.º 2
0
/*
 *	Calculate/check digest, and decode radius attributes.
 */
int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original,
	       const char *secret)
{
	DICT_ATTR		*attr;
	uint32_t		lvalue;
	uint32_t		vendorcode;
	VALUE_PAIR		**tail;
	VALUE_PAIR		*pair;
	uint8_t			*ptr;
	int			length;
	int			attribute;
	int			attrlen;
	int			vendorlen;
	radius_packet_t		*hdr;

	hdr = (radius_packet_t *)packet->data;

	/*
	 *	Before we allocate memory for the attributes, do more
	 *	sanity checking.
	 */
	ptr = hdr->data;
	length = packet->data_len - AUTH_HDR_LEN;
	while (length > 0) {
		uint8_t	msg_auth_vector[AUTH_VECTOR_LEN];
		uint8_t calc_auth_vector[AUTH_VECTOR_LEN];

		attrlen = ptr[1];

		switch (ptr[0]) {
		default:	/* don't do anything. */
			break;

			/*
			 *	Note that more than one Message-Authenticator
			 *	attribute is invalid.
			 */
		case PW_MESSAGE_AUTHENTICATOR:
			memcpy(msg_auth_vector, &ptr[2], sizeof(msg_auth_vector));
			memset(&ptr[2], 0, AUTH_VECTOR_LEN);

			switch (packet->code) {
			default:
			  break;

			case PW_AUTHENTICATION_ACK:
			case PW_AUTHENTICATION_REJECT:
			case PW_ACCESS_CHALLENGE:
			  if (original) {
				  memcpy(packet->data + 4, original->vector, AUTH_VECTOR_LEN);
			  }
			  break;
			}

			lrad_hmac_md5(packet->data, packet->data_len,
				      secret, strlen(secret), calc_auth_vector);
			if (memcmp(calc_auth_vector, msg_auth_vector,
				    sizeof(calc_auth_vector)) != 0) {
				char buffer[32];
				librad_log("Received packet from %s with invalid Message-Authenticator!  (Shared secret is incorrect.)",
					   ip_ntoa(buffer, packet->src_ipaddr));
				return 1;
			} /* else the message authenticator was good */

			/*
			 *	Reinitialize Authenticators.
			 */
			memcpy(&ptr[2], msg_auth_vector, AUTH_VECTOR_LEN);
			memcpy(packet->data + 4, packet->vector, AUTH_VECTOR_LEN);
			break;
		} /* switch over the attributes */

		ptr += attrlen;
		length -= attrlen;
	} /* loop over the packet, sanity checking the attributes */

	/*
	 *	Calculate and/or verify digest.
	 */
	switch(packet->code) {
		int rcode;

		case PW_AUTHENTICATION_REQUEST:
		case PW_STATUS_SERVER:
		case PW_DISCONNECT_REQUEST:
			/*
			 *	The authentication vector is random
			 *	nonsense, invented by the client.
			 */
			break;

		case PW_ACCOUNTING_REQUEST:
			if (calc_acctdigest(packet, secret) > 1) {
				char buffer[32];
				librad_log("Received Accounting-Request packet "
				    "from %s with invalid signature!  (Shared secret is incorrect.)",
				    ip_ntoa(buffer, packet->src_ipaddr));
				return 1;
			}
			break;

			/* Verify the reply digest */
		case PW_AUTHENTICATION_ACK:
		case PW_AUTHENTICATION_REJECT:
		case PW_ACCOUNTING_RESPONSE:
			rcode = calc_replydigest(packet, original, secret);
			if (rcode > 1) {
				char buffer[32];
				librad_log("Received %s packet "
					   "from %s with invalid signature (err=%d)!  (Shared secret is incorrect.)",
					   packet_codes[packet->code],
					   ip_ntoa(buffer, packet->src_ipaddr),
					   rcode);
				return 1;
			}
		  break;
	}

	/*
	 *	Extract attribute-value pairs
	 */
	ptr = hdr->data;
	length = packet->data_len - AUTH_HDR_LEN;
	packet->vps = NULL;
	tail = &packet->vps;

	vendorcode = 0;
	vendorlen  = 0;

	while(length > 0) {
		if (vendorlen > 0) {
			attribute = *ptr++ | (vendorcode << 16);
			attrlen   = *ptr++;
		} else {
			attribute = *ptr++;
			attrlen   = *ptr++;
		}

		attrlen -= 2;
		length  -= 2;

		/*
		 *	This could be a Vendor-Specific attribute.
		 *
		 */
		if ((vendorlen <= 0) &&
		    (attribute == PW_VENDOR_SPECIFIC) && 
		    (attrlen > 6)) {
			memcpy(&lvalue, ptr, 4);
			vendorcode = ntohl(lvalue);
			if (vendorcode != 0) {

				if (vendorcode == VENDORPEC_USR) {
					ptr += 4;
					memcpy(&lvalue, ptr, 4);
					/*printf("received USR %04x\n", ntohl(lvalue));*/
					attribute = (ntohl(lvalue) & 0xFFFF) |
							(vendorcode << 16);
					ptr += 4;
					attrlen -= 8;
					length -= 8;

				} else {
					ptr += 4;
					vendorlen = attrlen - 4;
					attribute = *ptr++ | (vendorcode << 16);
					attrlen   = *ptr++;
					attrlen -= 2;
					length -= 6;
				}
			}
			/*
			 *  Else the vendor wasn't found...
			 */
		}

		/*
		 *	FIXME: should we us paircreate() ?
		 */
		if ((pair = malloc(sizeof(VALUE_PAIR))) == NULL) {
			pairfree(&packet->vps);
			librad_log("out of memory");
			errno = ENOMEM;
			return -1;
		}
		
		memset(pair, 0, sizeof(VALUE_PAIR));
		if ((attr = dict_attrbyvalue(attribute)) == NULL) {
			snprintf(pair->name, sizeof(pair->name), "Attr-%d", attribute);
			pair->type = PW_TYPE_OCTETS;
		} else {
			strcpy(pair->name, attr->name);
			pair->type = attr->type;
			pair->flags = attr->flags;
		}
		pair->attribute = attribute;
		pair->length = attrlen;
		pair->operator = T_OP_EQ;
		pair->next = NULL;
		
		switch (pair->type) {
			
		case PW_TYPE_OCTETS:
		case PW_TYPE_ABINARY:
		case PW_TYPE_STRING:
			if (pair->flags.has_tag &&
			    pair->type == PW_TYPE_STRING) {
				int offset = 0;

				if ((pair->length > 0) && TAG_VALID(*ptr)) {
					pair->flags.tag = *ptr;
					pair->length--;
					offset = 1;
				} else if (pair->flags.encrypt == FLAG_ENCRYPT_TUNNEL_PASSWORD) {
					/*
					 * from RFC2868 - 3.5.  Tunnel-Password
					 * If the value of the Tag field is greater than
					 * 0x00 and less than or equal to 0x1F, it SHOULD
					 * be interpreted as indicating which tunnel
					 * (of several alternatives) this attribute pertains;
					 * otherwise, the Tag field SHOULD be ignored.
					 */
					pair->flags.tag = 0x00;
					if (pair->length > 0) pair->length--;
					offset = 1;
				} else {
				       pair->flags.tag = 0x00;
				}

				/*
				 *	pair->length may be zero here...
				 */
				memcpy(pair->strvalue, ptr + offset,
				       pair->length);
			} else {
				/* attrlen always < MAX_STRING_LEN */
				memcpy(pair->strvalue, ptr, attrlen);
			        pair->flags.tag = 0;
			}

			/*
			 *  FIXME: HACK for non-updated dictionaries.
			 *  REMOVE in a future release.
			 */
			if ((strcmp(pair->name, "Ascend-Send-Secret") == 0) ||
			    (strcmp(pair->name, "Ascend-Receive-Secret") == 0)) {
				pair->flags.encrypt = FLAG_ENCRYPT_ASCEND_SECRET;
			}
			if (pair->attribute == PW_USER_PASSWORD) {
				pair->flags.encrypt = FLAG_ENCRYPT_USER_PASSWORD;
			}

			/*
			 *	Decrypt passwords here.
			 */
			switch (pair->flags.encrypt) {
			default:
				break;

				/*
				 *  User-Password
				 */
			case FLAG_ENCRYPT_USER_PASSWORD:
				if (original) {
					rad_pwdecode((char *)pair->strvalue,
						     pair->length, secret,
						     (char *)original->vector);
				} else {
					rad_pwdecode((char *)pair->strvalue,
						     pair->length, secret,
						     (char *)packet->vector);
				}
				if (pair->attribute == PW_USER_PASSWORD) {
					pair->length = strlen(pair->strvalue);
				}
				break;

				/*
				 *  Tunnel-Password
				 */
			case FLAG_ENCRYPT_TUNNEL_PASSWORD:
				if (!original) {
					librad_log("ERROR: Tunnel-Password attribute in request: Cannot decrypt it.");
					return -1;
				}
			        rad_tunnel_pwdecode((char *)pair->strvalue,
						    &pair->length, 
						    secret,
						    (char *)original->vector);
				break;

				/*
				 *  Ascend-Send-Secret
				 *  Ascend-Receive-Secret
				 */
			case FLAG_ENCRYPT_ASCEND_SECRET:
				{
					uint8_t my_digest[AUTH_VECTOR_LEN];
					make_secret(my_digest,
						    original->vector,
						    secret, ptr);
					memcpy(pair->strvalue, my_digest,
					       AUTH_VECTOR_LEN );
					pair->strvalue[AUTH_VECTOR_LEN] = '\0';
					pair->length = strlen(pair->strvalue);
				}
				break;
			} /* switch over encryption flags */
			break;	/* from octets/string/abinary */
			
		case PW_TYPE_INTEGER:
		case PW_TYPE_DATE:
		case PW_TYPE_IPADDR:
			/*
			 *	Check for RFC compliance.  If the
			 *	attribute isn't compliant, turn it
			 *	into a string of raw octets.
			 *
			 *	Also set the lvalue to something
			 *	which should never match anything.
			 */
			if (attrlen != 4) {
				pair->type = PW_TYPE_OCTETS;
				memcpy(pair->strvalue, ptr, attrlen);
				pair->lvalue = 0xbad1bad1;
				break;
			}

      			memcpy(&lvalue, ptr, 4);

			if (attr->type != PW_TYPE_IPADDR) {
				pair->lvalue = ntohl(lvalue);
			} else {
				 /*
				  *  It's an IP address, keep it in network
				  *  byte order, and put the ASCII IP
				  *  address or host name into the string
				  *  value.
				  */
				pair->lvalue = lvalue;
				ip_ntoa(pair->strvalue, pair->lvalue);
			}

			/*
			 *  Only PW_TYPE_INTEGER should have tags.
			 */
			if (pair->flags.has_tag &&
			    pair->type == PW_TYPE_INTEGER) {
			        pair->flags.tag = (pair->lvalue >> 24) & 0xff;
				pair->lvalue &= 0x00ffffff;
			}

			if (attr->type == PW_TYPE_INTEGER) {
				DICT_VALUE *dval;
				dval = dict_valbyattr(pair->attribute,
						      pair->lvalue);
				if (dval) {
					strNcpy(pair->strvalue,
						dval->name,
						sizeof(pair->strvalue));
				}
			}
			break;
			
		default:
			DEBUG("    %s (Unknown Type %d)\n",
			      attr->name,attr->type);
			free(pair);
			pair = NULL;
			break;
		}
		
		if (pair) {
			debug_pair(pair);
			*tail = pair;
			tail = &pair->next;
		}

		ptr += attrlen;
		length -= attrlen;
		if (vendorlen > 0) vendorlen -= (attrlen + 2);
	}