Beispiel #1
0
/*
 *	CoA realms via Operator-Name.  Because the realm isn't in a
 *	User-Name, concepts like "prefix" and "suffix' don't matter.
 */
static rlm_rcode_t realm_recv_coa(UNUSED void *instance, REQUEST *request)
{
	VALUE_PAIR *vp;
	REALM *realm;

	if (pairfind(request->packet->vps, PW_REALM, 0, TAG_ANY) != NULL) {
		RDEBUG2("Request already proxied.  Ignoring.");
		return RLM_MODULE_OK;
	}

	vp = pairfind(request->packet->vps, PW_OPERATOR_NAME, 0, TAG_ANY);
	if (!vp) return RLM_MODULE_NOOP;
	
	/*
	 *	Catch the case of broken dictionaries.
	 */
	if (vp->da->type != PW_TYPE_STRING) return RLM_MODULE_NOOP;

	/*
	 *	The string is too short.
	 */
	if (vp->length == 1) return RLM_MODULE_NOOP;

	/*
	 *	'1' means "the rest of the string is a realm"
	 */
	if (vp->vp_strvalue[0] != '1') return RLM_MODULE_NOOP;

	realm = realm_find(vp->vp_strvalue + 1);
	if (!realm) return RLM_MODULE_NOTFOUND;

	if (!realm->coa_pool) {
		RDEBUG2("CoA realm is LOCAL.");
		return RLM_MODULE_OK;
	}

	/*
	 *	Maybe add a Proxy-To-Realm attribute to the request.
	 */
	RDEBUG2("Preparing to proxy authentication request to realm \"%s\"\n",
	       realm->name);
	pairmake_config("Proxy-To-Realm", realm->name, T_OP_EQ);

	return RLM_MODULE_UPDATED; /* try the next module */
}
Beispiel #2
0
/*
 *	Internal function to cut down on duplicated code.
 *
 *	Returns -1 on failure, 0 on no failure.  returnrealm
 *	is NULL on don't proxy, realm otherwise.
 */
static int check_for_realm(void *instance, REQUEST *request, REALM **returnrealm)
{
	char *namebuf;
	char *username;
	char const *realmname = NULL;
	char *ptr;
	VALUE_PAIR *vp;
	REALM *realm;

	struct realm_config_t *inst = instance;

	/* initiate returnrealm */
	*returnrealm = NULL;

	/*
	 *	If the request has a proxy entry, then it's a proxy
	 *	reply, and we're walking through the module list again.
	 *
	 *	In that case, don't bother trying to proxy the request
	 *	again.
	 *
	 *	Also, if there's no User-Name attribute, we can't
	 *	proxy it, either.
	 */
	if ((!request->username)
#ifdef WITH_PROXY
	    || (request->proxy != NULL)
#endif
	    ) {
	
		RDEBUG2("Proxy reply, or no User-Name.  Ignoring.");
		return RLM_MODULE_OK;
	}

	/*
	 *      Check for 'Realm' attribute.  If it exists, then we've proxied
	 *      it already ( via another rlm_realm instance ) and should return.
	 */

	if (pairfind(request->packet->vps, PW_REALM, 0, TAG_ANY) != NULL ) {
		RDEBUG2("Request already proxied.  Ignoring.");
		return RLM_MODULE_OK;
	}

	/*
	 *	We will be modifing this later, so we want our own copy
	 *	of it.
	 */
	namebuf = talloc_strdup(request,  request->username->vp_strvalue);
	username = namebuf;

	switch(inst->format) {
	case REALM_FORMAT_SUFFIX:

	  /* DEBUG2("  rlm_realm: Checking for suffix after \"%c\"", inst->delim[0]); */
		ptr = strrchr(username, inst->delim[0]);
		if (ptr) {
			*ptr = '\0';
			realmname = ptr + 1;
		}
		break;

	case REALM_FORMAT_PREFIX:

		/* DEBUG2("  rlm_realm: Checking for prefix before \"%c\"", inst->delim[0]); */

		ptr = strchr(username, inst->delim[0]);
		if (ptr) {
			*ptr = '\0';
		     ptr++;
		     realmname = username;
		     username = ptr;
		}
		break;

	default:
		realmname = NULL;
		break;
	}

	/*
	 *	Print out excruciatingly descriptive debugging messages
	 *	for the people who find it too difficult to think about
	 *	what's going on.
	 */
	if (realmname) {
		RDEBUG2("Looking up realm \"%s\" for User-Name = \"%s\"",
		       realmname, request->username->vp_strvalue);
	} else {
		if (inst->ignore_null ) {
			RDEBUG2("No '%c' in User-Name = \"%s\", skipping NULL due to config.",
			inst->delim[0], request->username->vp_strvalue);
			talloc_free(namebuf);
			return RLM_MODULE_NOOP;
		}
		RDEBUG2("No '%c' in User-Name = \"%s\", looking up realm NULL",
		       inst->delim[0], request->username->vp_strvalue);
	}

	/*
	 *	Allow DEFAULT realms unless told not to.
	 */
	realm = realm_find(realmname);
	if (!realm) {
		RDEBUG2("No such realm \"%s\"",
			(!realmname) ? "NULL" : realmname);
		talloc_free(namebuf);
		return RLM_MODULE_NOOP;
	}
	if( inst->ignore_default &&
	    (strcmp(realm->name, "DEFAULT")) == 0) {
		RDEBUG2("Found DEFAULT, but skipping due to config.");
		talloc_free(namebuf);
		return RLM_MODULE_NOOP;
	}

	RDEBUG2("Found realm \"%s\"", realm->name);

	/*
	 *	If we've been told to strip the realm off, then do so.
	 */
	if (realm->striprealm) {
		/*
		 *	Create the Stripped-User-Name attribute, if it
		 *	doesn't exist.
		 *
		 */
		if (request->username->da->attr != PW_STRIPPED_USER_NAME) {
			vp = radius_paircreate(request, &request->packet->vps,
					       PW_STRIPPED_USER_NAME, 0);
			RDEBUG2("Adding Stripped-User-Name = \"%s\"", username);
		} else {
			vp = request->username;
			RDEBUG2("Setting Stripped-User-Name = \"%s\"", username);
		}

		pairstrcpy(vp, username);
		request->username = vp;
	}

	/*
	 *	Add the realm name to the request.
	 *	If the realm is a regex, the use the realm as entered
	 *	by the user.  Otherwise, use the configured realm name,
	 *	as realm name comparison is case insensitive.  We want
	 *	to use the configured name, rather than what the user
	 *	entered.
	 */
	if (realm->name[0] != '~') realmname = realm->name;
	pairmake_packet("Realm", realmname, T_OP_EQ);
	RDEBUG2("Adding Realm = \"%s\"", realmname);

	talloc_free(namebuf);
	realmname = username = NULL;

	/*
	 *	Figure out what to do with the request.
	 */
	switch (request->packet->code) {
	default:
		RDEBUG2("Unknown packet code %d\n",
		       request->packet->code);
		return RLM_MODULE_OK;		/* don't do anything */

		/*
		 *	Perhaps accounting proxying was turned off.
		 */
	case PW_ACCOUNTING_REQUEST:
		if (!realm->acct_pool) {
			RDEBUG2("Accounting realm is LOCAL.");
			return RLM_MODULE_OK;
		}
		break;

		/*
		 *	Perhaps authentication proxying was turned off.
		 */
	case PW_AUTHENTICATION_REQUEST:
		if (!realm->auth_pool) {
			RDEBUG2("Authentication realm is LOCAL.");
			return RLM_MODULE_OK;
		}
		break;
	}

#ifdef WITH_PROXY
	RDEBUG2("Proxying request from user %s to realm %s",
	       request->username->vp_strvalue, realm->name);

	/*
	 *	Skip additional checks if it's not an accounting
	 *	request.
	 */
	if (request->packet->code != PW_ACCOUNTING_REQUEST) {
		*returnrealm = realm;
		return RLM_MODULE_UPDATED;
	}

	/*
	 *	FIXME: Each server should have a unique server key,
	 *	and put it in the accounting packet.  Every server
	 *	should know about the keys, and NOT proxy requests to
	 *	a server with key X if the packet already contains key
	 *	X.
	 */

	/*
	 *      If this request has arrived from another freeradius server
	 *      that has already proxied the request, we don't need to do
	 *      it again.
	 */
	vp = pairfind(request->packet->vps, PW_FREERADIUS_PROXIED_TO, 0, TAG_ANY);
	if (vp && (request->packet->src_ipaddr.af == AF_INET)) {
		int i;
		fr_ipaddr_t my_ipaddr;

		my_ipaddr.af = AF_INET;
		my_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;

		/*
		 *	Loop over the home accounting servers for this
		 *	realm.  If one of them has the same IP as the
		 *	FreeRADIUS-Proxied-To attribute, then the
		 *	packet has already been sent there.  Don't
		 *	send it there again.
		 */
		for (i = 0; i < realm->acct_pool->num_home_servers; i++) {
			if (fr_ipaddr_cmp(&realm->acct_pool->servers[i]->ipaddr,
					    &my_ipaddr) == 0) {
				RDEBUG2("Suppressing proxy due to FreeRADIUS-Proxied-To");
				return RLM_MODULE_OK;
			}
		}

		/*
		 *	See detail_recv() in src/main/listen.c for the
		 *	additional checks.
		 */
#ifdef WITH_DETAIL
	} else if ((request->listener->type == RAD_LISTEN_DETAIL) &&
		   !fr_inaddr_any(&request->packet->src_ipaddr)) {
		int i;

		/*
		 *	Loop over the home accounting servers for this
		 *	realm.  If one of them has the same IP as the
		 *	FreeRADIUS-Proxied-To attribute, then the
		 *	packet has already been sent there.  Don't
		 *	send it there again.
		 */
		for (i = 0; i < realm->acct_pool->num_home_servers; i++) {
			if ((fr_ipaddr_cmp(&realm->acct_pool->servers[i]->ipaddr,
					     &request->packet->src_ipaddr) == 0) &&
			    (realm->acct_pool->servers[i]->port == request->packet->src_port)) {
				RDEBUG2("Suppressing proxy because packet was already sent to a server in that realm");
				return RLM_MODULE_OK;
			}
		}
#endif	/* WITH_DETAIL */
	}
#endif	/* WITH_PROXY */

	/*
	 *	We got this far, which means we have a realm, set returnrealm
	 */
	*returnrealm = realm;

	return RLM_MODULE_UPDATED;
}
Beispiel #3
0
/*
 *	Process and reply to an authentication request
 *
 *	The return value of this function isn't actually used right now, so
 *	it's not entirely clear if it is returning the right things. --Pac.
 */
int rad_authenticate(REQUEST *request)
{
	VALUE_PAIR	*namepair;
	VALUE_PAIR	*check_item;
	VALUE_PAIR	*auth_item;
	VALUE_PAIR	*module_msg;
	VALUE_PAIR	*tmp = NULL;
	int		result, r;
	char		umsg[MAX_STRING_LEN + 1];
	const char	*user_msg = NULL;
	const char	*password;
	char		logstr[1024];
	char		autz_retry = 0;
	int		autz_type = 0;

	password = "";

	/*
	 *	If this request got proxied to another server,
	 *	AND it was an authentication request, then we need
	 *	to add an initial Auth-Type: Auth-Accept for success,
	 *	Auth-Reject for fail. We also need to add the reply
	 *	pairs from the server to the initial reply.
	 *
	 *	Huh?  If the request wasn't an authentication request,
	 *	WTF are we doing here?
	 */
	if ((request->proxy_reply) &&
	    (request->packet->code == PW_AUTHENTICATION_REQUEST)) {
		tmp = paircreate(PW_AUTH_TYPE, PW_TYPE_INTEGER);
		if (tmp == NULL) {
			radlog(L_ERR|L_CONS, "no memory");
			exit(1);
		}

		/*
		 *	Challenges are punted back to the NAS
		 *	without any further processing.
		 */
		if (request->proxy_reply->code == PW_ACCESS_CHALLENGE) {
			request->reply->code = PW_ACCESS_CHALLENGE;
			return RLM_MODULE_HANDLED;
		}

		/*
		 *	Reply of ACCEPT means accept, ALL other
		 *	replies mean reject.  This is fail-safe.
		 */
		if (request->proxy_reply->code == PW_AUTHENTICATION_ACK)
			tmp->lvalue = PW_AUTHTYPE_ACCEPT;
		else
			tmp->lvalue = PW_AUTHTYPE_REJECT;
		pairadd(&request->config_items, tmp);

		/*
		 *	If it's an Access-Reject, then do NOT do any
		 *	authorization or authentication.  They're being
		 *	rejected, so we minimize the amount of work
		 *	done by the server, by rejecting them here.
		 */
		if ((request->proxy_reply->code != PW_AUTHENTICATION_ACK) &&
		    (request->proxy_reply->code != PW_ACCESS_CHALLENGE)) {
			rad_authlog("Login incorrect (Home Server says so)", request, 0);
			request->reply->code = PW_AUTHENTICATION_REJECT;
			rad_postauth_reject(request);
			return RLM_MODULE_REJECT;
		}
	}

	/*
	 *	Get the username from the request.
	 *
	 *	Note that namepair MAY be NULL, in which case there
	 *	is no User-Name attribute in the request.
	 */
	namepair = request->username;

	/*
	 *	Look for, and cache, passwords.
	 */
	if (!request->password) {
		request->password = pairfind(request->packet->vps,
					     PW_PASSWORD);
	}

	/*
	 *	Discover which password we want to use.
	 */
	auth_item = request->password;
	if (auth_item) {
		password = (const char *)auth_item->strvalue;

	} else {
		/*
		 *	Maybe there's a CHAP-Password?
		 */
		if ((auth_item = pairfind(request->packet->vps,
				PW_CHAP_PASSWORD)) != NULL) {
			password = "******";

		} else {
			/*
			 *	No password we recognize.
			 */
			password = "******";
		}
	}
	request->password = auth_item;

	/*
	 *	Get the user's authorization information from the database
	 */
autz_redo:
	r = module_authorize(autz_type, request);
	if (r != RLM_MODULE_NOTFOUND &&
	    r != RLM_MODULE_NOOP &&
	    r != RLM_MODULE_OK &&
	    r != RLM_MODULE_UPDATED) {
		if (r != RLM_MODULE_FAIL && r != RLM_MODULE_HANDLED) {
			if ((module_msg = pairfind(request->packet->vps,
					PW_MODULE_FAILURE_MESSAGE)) != NULL){
				char msg[MAX_STRING_LEN+16];
				snprintf(msg, sizeof(msg), "Invalid user (%s)",
					 module_msg->strvalue);
				rad_authlog(msg,request,0);
			} else {
				rad_authlog("Invalid user", request, 0);
			}
			request->reply->code = PW_AUTHENTICATION_REJECT;
		}
		return r;
	}
	if (!autz_retry){
		VALUE_PAIR	*autz_type_item = NULL;
		autz_type_item = pairfind(request->config_items, PW_AUTZ_TYPE);
		if (autz_type_item){
			autz_type = autz_type_item->lvalue;
			autz_retry = 1;
			goto autz_redo;
		}
	}

	/*
	 *	If we haven't already proxied the packet, then check
	 *	to see if we should.  Maybe one of the authorize
	 *	modules has decided that a proxy should be used. If
	 *	so, get out of here and send the packet.
	 */
	if ((request->proxy == NULL) &&
	    ((tmp = pairfind(request->config_items, PW_PROXY_TO_REALM)) != NULL)) {
		REALM *realm;

		/*
		 *	Catch users who set Proxy-To-Realm to a LOCAL
		 *	realm (sigh).
		 */
		realm = realm_find(tmp->strvalue, 0);
		rad_assert((realm == NULL) || (realm->ipaddr.af == AF_INET));
		if (realm && (realm->ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_NONE))) {
			DEBUG2("  WARNING: You set Proxy-To-Realm = %s, but it is a LOCAL realm!  Cancelling invalid proxy request.", realm->realm);
		} else {
			/*
			 *	Don't authenticate, as the request is
			 *	proxied.
			 */
			return RLM_MODULE_OK;
		}
	}

	/*
	 *	Perhaps there is a Stripped-User-Name now.
	 */
	namepair = request->username;

	/*
	 *	Validate the user
	 */
	do {
		result = rad_check_password(request);
		if (result > 0) {
			/* don't reply! */
			return RLM_MODULE_HANDLED;
		}
	} while(0);

	/*
	 *	Failed to validate the user.
	 *
	 *	We PRESUME that the code which failed will clean up
	 *	request->reply->vps, to be ONLY the reply items it
	 *	wants to send back.
	 */
	if (result < 0) {
		DEBUG2("auth: Failed to validate the user.");
		request->reply->code = PW_AUTHENTICATION_REJECT;

		if ((module_msg = pairfind(request->packet->vps,PW_MODULE_FAILURE_MESSAGE)) != NULL){
			char msg[MAX_STRING_LEN+19];

			snprintf(msg, sizeof(msg), "Login incorrect (%s)",
				 module_msg->strvalue);
			rad_authlog(msg, request, 0);
		} else {
			rad_authlog("Login incorrect", request, 0);
		}

		/* double check: maybe the secret is wrong? */
		if ((debug_flag > 1) && (auth_item != NULL) &&
				(auth_item->attribute == PW_PASSWORD)) {
			u_char *p;

			p = auth_item->strvalue;
			while (*p != '\0') {
				if (!isprint((int) *p)) {
					log_debug("  WARNING: Unprintable characters in the password.\n\t  Double-check the shared secret on the server and the NAS!");
					break;
				}
				p++;
			}
		}
	}

	if (result >= 0 &&
	    (check_item = pairfind(request->config_items, PW_SIMULTANEOUS_USE)) != NULL) {
		VALUE_PAIR	*session_type;
		int		sess_type = 0;

		session_type = pairfind(request->config_items, PW_SESSION_TYPE);
		if (session_type)
			sess_type = session_type->lvalue;

		/*
		 *	User authenticated O.K. Now we have to check
		 *	for the Simultaneous-Use parameter.
		 */
		if (namepair &&
		    (r = module_checksimul(sess_type,request, check_item->lvalue)) != 0) {
			char mpp_ok = 0;

			if (r == 2){
				/* Multilink attempt. Check if port-limit > simultaneous-use */
				VALUE_PAIR *port_limit;

				if ((port_limit = pairfind(request->reply->vps, PW_PORT_LIMIT)) != NULL &&
					port_limit->lvalue > check_item->lvalue){
					DEBUG2("main auth: MPP is OK");
					mpp_ok = 1;
				}
			}
			if (!mpp_ok){
				if (check_item->lvalue > 1) {
		  		snprintf(umsg, sizeof(umsg),
							"\r\nYou are already logged in %d times  - access denied\r\n\n",
							(int)check_item->lvalue);
					user_msg = umsg;
				} else {
					user_msg = "\r\nYou are already logged in - access denied\r\n\n";
				}

				request->reply->code = PW_AUTHENTICATION_REJECT;

				/*
				 *	They're trying to log in too many times.
				 *	Remove ALL reply attributes.
				 */
				pairfree(&request->reply->vps);
				tmp = pairmake("Reply-Message", user_msg, T_OP_SET);
				request->reply->vps = tmp;

				snprintf(logstr, sizeof(logstr), "Multiple logins (max %d) %s",
					check_item->lvalue,
					r == 2 ? "[MPP attempt]" : "");
				rad_authlog(logstr, request, 1);

				result = -1;
			}
		}
	}

	/*
	 *	Result should be >= 0 here - if not, it means the user
	 *	is rejected, so we just process post-auth and return.
	 */
	if (result < 0) {
		rad_postauth_reject(request);
		return RLM_MODULE_REJECT;
	}

	/*
	 *	We might need this later.  The 'password' string
	 *	is NOT used anywhere below here, except for logging,
	 *	so it should be safe...
	 */
	if ((auth_item != NULL) && (auth_item->attribute == PW_CHAP_PASSWORD)) {
		password = "******";
	}

	/*
	 *	Add the port number to the Framed-IP-Address if
	 *	vp->addport is set.
	 */
	if (((tmp = pairfind(request->reply->vps,
			     PW_FRAMED_IP_ADDRESS)) != NULL) &&
	    (tmp->flags.addport != 0)) {
		VALUE_PAIR *vpPortId;

		/*
		 *  Find the NAS port ID.
		 */
		if ((vpPortId = pairfind(request->packet->vps,
					 PW_NAS_PORT)) != NULL) {
		  unsigned long tvalue = ntohl(tmp->lvalue);
		  tmp->lvalue = htonl(tvalue + vpPortId->lvalue);
		  tmp->flags.addport = 0;
		  ip_ntoa(tmp->strvalue, tmp->lvalue);
		} else {
			DEBUG2("WARNING: No NAS-Port attribute in request.  CANNOT return a Framed-IP-Address + NAS-Port.\n");
			pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS);
		}
	}

	/*
	 *	Set the reply to Access-Accept, if it hasn't already
	 *	been set to something.  (i.e. Access-Challenge)
	 */
	if (request->reply->code == 0)
	  request->reply->code = PW_AUTHENTICATION_ACK;

	if ((module_msg = pairfind(request->packet->vps,PW_MODULE_SUCCESS_MESSAGE)) != NULL){
		char msg[MAX_STRING_LEN+12];

		snprintf(msg, sizeof(msg), "Login OK (%s)",
			 module_msg->strvalue);
		rad_authlog(msg, request, 1);
	} else {
		rad_authlog("Login OK", request, 1);
	}

	/*
	 *	Run the modules in the 'post-auth' section.
	 */
	result = rad_postauth(request);

	return result;
}
/*
 *      Find the named realm in the database.  Create the
 *      set of attribute-value pairs to check and reply with
 *      for this realm from the database.
 */
static int attr_filter_postproxy(void *instance, REQUEST *request)
{
	struct attr_filter_instance *inst = instance;
	VALUE_PAIR	*request_pairs;
	VALUE_PAIR	**reply_items;
	VALUE_PAIR	*reply_item;
	VALUE_PAIR	*reply_tmp = NULL;
	VALUE_PAIR	*check_item;
	PAIR_LIST	*pl;
	int		found = 0;
        int		compare;
        int		pass, fail;
#ifdef HAVE_REGEX_H
	regex_t		reg;
#endif
	VALUE_PAIR	*realmpair;
	REALM		*realm;
	char		*realmname;

	/*
	 *	It's not a proxy reply, so return NOOP
	 */

	if( request->proxy == NULL ) {
		return( RLM_MODULE_NOOP );
	}

	request_pairs = request->packet->vps;
	reply_items = &request->proxy_reply->vps;

	/*
	 *	Get the realm.  Can't use request->config_items as
	 *	that gets freed by rad_authenticate....  use the one
	 *	set in the original request vps
	 */
	realmpair = pairfind(request_pairs, PW_REALM);
	if(!realmpair) {
		/*    Can't find a realm, so no filtering of attributes
		 *    or should we use a DEFAULT entry?
		 *    For now, just return NOTFOUND. (maybe NOOP?)
		 */
		return RLM_MODULE_NOTFOUND;
	}

	realmname = (char *) realmpair->strvalue;
	realm = realm_find(realmname, FALSE);

	/*
	 *      Find the attr_filter profile entry for the realm.
	 */
	for(pl = inst->attrs; pl; pl = pl->next) {

	    /*
	     *  If the current entry is NOT a default,
	     *  AND the realm does NOT match the current entry,
	     *  then skip to the next entry.
	     */
	    if ( (strcmp(pl->name, "DEFAULT") != 0) &&
		 (strcmp(realmname, pl->name) != 0) )  {
		    continue;
	    }

	    DEBUG2("  attr_filter: Matched entry %s at line %d",
		    pl->name, pl->lineno);
	    found = 1;

	    check_item = pl->check;

	    while( check_item != NULL ) {

		    /*
		     *    If it is a SET operator, add the attribute to
		     *    the reply list without checking reply_items.
		     */

		    if( check_item->operator == T_OP_SET ) {
			mypairappend(check_item, &reply_tmp);
		    }
		    check_item = check_item->next;

	    }  /* while( check_item != NULL ) */

	    /*
	     * Iterate through the reply items,
	     * comparing each reply item to every rule,
	     * then moving it to the reply_tmp list only if it matches all
	     * rules for that attribute.
	     * IE, Idle-Timeout is moved only if it matches
	     * all rules that describe an Idle-Timeout.
	     */

	    for( reply_item = *reply_items;
		 reply_item != NULL;
		 reply_item = reply_item->next ) {

		/* reset the pass,fail vars for each reply item */
		pass = fail = 0;

		/* reset the check_item pointer to the beginning of the list */
		check_item = pl->check;

		while( check_item != NULL ) {

		    if(reply_item->attribute == check_item->attribute) {

			compare = simplepaircmp(request, reply_item,
                                                check_item);
			switch(check_item->operator) {

			    case T_OP_SET:	/* nothing to do for set */
				break;
			    case T_OP_EQ:
				default:
				radlog(L_ERR, "Invalid operator for item %s: "
				              "reverting to '=='",
					      check_item->name);

			    case T_OP_CMP_TRUE:       /* compare always == 0 */
			    case T_OP_CMP_FALSE:      /* compare always == 1 */
			    case T_OP_CMP_EQ:
				if (compare == 0) {
				    pass++;
				} else {
				    fail++;
				}
				break;

			    case T_OP_NE:
				if (compare != 0) {
				    pass++;
				} else {
				    fail++;
				}
				break;

			    case T_OP_LT:
				if (compare < 0) {
				    pass++;
				} else {
				    fail++;
				}
				break;

			    case T_OP_GT:
				if (compare > 0) {
				    pass++;
				} else {
				    fail++;
				}
				break;

			    case T_OP_LE:
				if (compare <= 0) {
				    pass++;
				} else {
				    fail++;
				}
				break;

			    case T_OP_GE:
				if (compare >= 0) {
				    pass++;
				} else {
				    fail++;
				}
				break;
#ifdef HAVE_REGEX_H
			    case T_OP_REG_EQ:
				regcomp(&reg, (char *)check_item->strvalue, 0);
				compare = regexec(&reg,
						  (char *)reply_item->strvalue,
						  0, NULL, 0);
				regfree(&reg);
				if (compare == 0) {
				    pass++;
				} else {
				    fail++;
				}
				break;

			    case T_OP_REG_NE:
				regcomp(&reg, (char *)check_item->strvalue, 0);
				compare = regexec(&reg,
						  (char *)reply_item->strvalue,
						  0, NULL, 0);
				regfree(&reg);
				if (compare != 0) {
				    pass++;
				} else {
				    fail++;
				}
				break;
#endif
			}  /* switch( check_item->operator ) */

		    }  /* if reply == check */

		    check_item = check_item->next;

		}  /* while( check ) */

		/* only move attribute if it passed all rules */
		    if (fail == 0 && pass > 0) {
			mypairappend( reply_item, &reply_tmp);
		    }

	    }  /* for( reply ) */

	    /* If we shouldn't fall through, break */
	    if(!fallthrough(pl->check))
		break;
	}

	pairfree(&request->proxy_reply->vps);
	request->proxy_reply->vps = reply_tmp;

	/*
	 *	See if we succeeded.  If we didn't find the realm,
	 *	then exit from the module.
	 */
	if (!found)
	    return RLM_MODULE_OK;

	/*
	 *	Remove server internal parameters.
	 */
	pairdelete(reply_items, PW_FALL_THROUGH);

	return RLM_MODULE_UPDATED;
}
Beispiel #5
0
/*
 *	Internal function to cut down on duplicated code.
 *
 *	Returns -1 on failure, 0 on no failure.  returnrealm
 *	is NULL on don't proxy, realm otherwise.
 */
static int check_for_realm(void *instance, REQUEST *request, REALM **returnrealm)
{
	char namebuf[MAX_STRING_LEN];
	char *username;
	char *realmname = NULL;
	char *ptr;
	VALUE_PAIR *vp;
	REALM *realm;

        struct realm_config_t *inst = instance;

	/* initiate returnrealm */
	*returnrealm = NULL;

	/*
	 *	If the request has a proxy entry, then it's a proxy
	 *	reply, and we're walking through the module list again.
	 *
	 *	In that case, don't bother trying to proxy the request
	 *	again.
	 *
	 *	Also, if there's no User-Name attribute, we can't
	 *	proxy it, either.
	 */
	if ((request->proxy != NULL) ||
	    (request->username == NULL)) {
		DEBUG2("    rlm_realm: Proxy reply, or no User-Name.  Ignoring.");
		return 0;
	}

	/*
	 *      Check for 'Realm' attribute.  If it exists, then we've proxied
	 *      it already ( via another rlm_realm instance ) and should return.
	 */

	if ( (vp = pairfind(request->packet->vps, PW_REALM)) != NULL ) {
	        DEBUG2("    rlm_realm: Request already proxied.  Ignoring.");
		return 0;
	}

	/*
	 *	We will be modifing this later, so we want our own copy
	 *	of it.
	 */
	strNcpy(namebuf, (char *)request->username->strvalue, sizeof(namebuf));
	username = namebuf;

	switch(inst->format)
	{

	case REALM_FORMAT_SUFFIX:

	  /* DEBUG2("  rlm_realm: Checking for suffix after \"%c\"", inst->delim[0]); */
		realmname = strrchr(username, inst->delim[0]);
		if (realmname) {
			*realmname = '\0';
			realmname++;
		}
		break;

	case REALM_FORMAT_PREFIX:

		/* DEBUG2("  rlm_realm: Checking for prefix before \"%c\"", inst->delim[0]); */

		ptr = strchr(username, inst->delim[0]);
		if (ptr) {
			*ptr = '\0';
		     ptr++;
		     realmname = username;
		     username = ptr;
		}
		break;

	default:
		realmname = NULL;
		break;
	}

	/*
	 *	Print out excruciatingly descriptive debugging messages
	 *	for the people who find it too difficult to think about
	 *	what's going on.
	 */
	if (realmname) {
		DEBUG2("    rlm_realm: Looking up realm \"%s\" for User-Name = \"%s\"",
		       realmname, request->username->strvalue);
	} else {
		if( inst->ignore_null ) {
			DEBUG2("    rlm_realm: No '%c' in User-Name = \"%s\", skipping NULL due to config.",
			inst->delim[0], request->username->strvalue);
			return 0;
		}
		DEBUG2("    rlm_realm: No '%c' in User-Name = \"%s\", looking up realm NULL",
		       inst->delim[0], request->username->strvalue);
	}

	/*
	 *	Allow DEFAULT realms unless told not to.
	 */
	realm = realm_find(realmname, (request->packet->code == PW_ACCOUNTING_REQUEST));
	if (!realm) {
		DEBUG2("    rlm_realm: No such realm \"%s\"",
		       (realmname == NULL) ? "NULL" : realmname);
		return 0;
	}
	if( inst->ignore_default &&
	    (strcmp(realm->realm, "DEFAULT")) == 0) {
		DEBUG2("    rlm_realm: Found DEFAULT, but skipping due to config.");
		return 0;
	}


	DEBUG2("    rlm_realm: Found realm \"%s\"", realm->realm);

	/*
	 *	If we've been told to strip the realm off, then do so.
	 */
	if (realm->striprealm) {
		/*
		 *	Create the Stripped-User-Name attribute, if it
		 *	doesn't exist.
		 *
		 */
		if (request->username->attribute != PW_STRIPPED_USER_NAME) {
			vp = paircreate(PW_STRIPPED_USER_NAME, PW_TYPE_STRING);
			if (!vp) {
				radlog(L_ERR|L_CONS, "no memory");
				return -1;
			}
			pairadd(&request->packet->vps, vp);
			DEBUG2("    rlm_realm: Adding Stripped-User-Name = \"%s\"", username);
		} else {
			vp = request->username;
			DEBUG2("    rlm_realm: Setting Stripped-User-Name = \"%s\"", username);
		}

		strcpy(vp->strvalue, username);
		vp->length = strlen((char *)vp->strvalue);
		request->username = vp;
	}

	DEBUG2("    rlm_realm: Proxying request from user %s to realm %s",
	       username, realm->realm);

	/*
	 *	Add the realm name to the request.
	 */
	pairadd(&request->packet->vps, pairmake("Realm", realm->realm,
						T_OP_EQ));
	DEBUG2("    rlm_realm: Adding Realm = \"%s\"", realm->realm);

	/*
	 *	Figure out what to do with the request.
	 */
	switch (request->packet->code) {
	default:
		DEBUG2("    rlm_realm: Unknown packet code %d\n",
		       request->packet->code);
		return 0;		/* don't do anything */

		/*
		 *	Perhaps accounting proxying was turned off.
		 */
	case PW_ACCOUNTING_REQUEST:
		if (realm->acct_ipaddr == htonl(INADDR_NONE)) {
			DEBUG2("    rlm_realm: Accounting realm is LOCAL.");
			return 0;
		}

		if (realm->acct_port == 0) {
			DEBUG2("    rlm_realm: acct_port is not set.  Proxy cancelled.");
			return 0;
		}
		break;

		/*
		 *	Perhaps authentication proxying was turned off.
		 */
	case PW_AUTHENTICATION_REQUEST:
		if (realm->ipaddr == htonl(INADDR_NONE)) {
			DEBUG2("    rlm_realm: Authentication realm is LOCAL.");
			return 0;
		}

		if (realm->auth_port == 0) {
			DEBUG2("    rlm_realm: auth_port is not set.  Proxy cancelled.");
			return 0;
		}
		break;
	}

	/*
	 *      If this request has arrived from another freeradius server
	 *      that has already proxied the request, we don't need to do
	 *      it again.
	 */
	for (vp = request->packet->vps; vp; vp = vp->next) {
		if (vp->attribute == PW_FREERADIUS_PROXIED_TO) {
			if (request->packet->code == PW_AUTHENTICATION_REQUEST &&
			    vp->lvalue == realm->ipaddr) {
				DEBUG2("    rlm_realm: Request not proxied due to Freeradius-Proxied-To");
				return 0;
			}
			if (request->packet->code == PW_ACCOUNTING_REQUEST &&
			    vp->lvalue == realm->acct_ipaddr) {
				DEBUG2("    rlm_realm: Request not proxied due to Freeradius-Proxied-To");
				return 0;
			}
		}
        }

	/*
	 *	We got this far, which means we have a realm, set returnrealm
	 */
	*returnrealm = realm;
	return 0;
}