diff -ur radiusd/src/modules/rlm_policy/evaluate.c freeradius-1.1.0/src/modules/rlm_policy/evaluate.c
--- radiusd/src/modules/rlm_policy/evaluate.c	2005-09-27 19:59:11.000000000 -0400
+++ freeradius-1.1.0/src/modules/rlm_policy/evaluate.c	2005-10-12 13:09:21.000000000 -0400
@@ -344,13 +342,15 @@
 	rad_assert(pitem != NULL);
 	rad_assert(state->depth >= 0);
 
- redo:
+redo:
 	if (state->depth == 0) {
 		*pitem = NULL;
 		return 0;
 	}
 
 	*pitem = state->stack[state->depth - 1];
+	if(state->depth > 1)
+		state->depth--;
 
 	/*
 	 *	Named policies are on the stack for catching recursion.
@@ -490,7 +490,7 @@
 {
 	int rcode;
 	const policy_condition_t *this;
-	VALUE_PAIR *vp;
+	VALUE_PAIR *vp = NULL;
 	const char *data = NULL;
 	int compare;
 #ifdef HAVE_REGEX_H
@@ -498,6 +498,7 @@
 #endif
 	char buffer[256];
 	char lhs_buffer[2048];
+	int next_vp = 0;
 
 	this = (const policy_condition_t *) item;
 
@@ -533,7 +534,9 @@
 		rcode = evaluate_condition(state, this->child);
 		rcode = (rcode == FALSE); /* reverse sense of test */
 		break;
-
+	
+	case POLICY_LEX_CMP_FALSE: /* no existence */
+		/*fall through*/
 	case POLICY_LEX_CMP_TRUE: /* existence */
 		if (this->lhs_type == POLICY_LEX_BARE_WORD) {
 			vp = find_vp(state->request, this->lhs);
@@ -541,6 +544,8 @@
 		} else {
 			rcode = (data != NULL);
 		}
+		if (this->compare == POLICY_LEX_CMP_FALSE)
+			rcode = !rcode;
 		break;
 
 	default:		/* process other comparisons */
@@ -561,9 +566,15 @@
 
 		if (this->lhs_type == POLICY_LEX_BARE_WORD) {
 			VALUE_PAIR *myvp;
+			vp = find_vp(state->request, this->lhs);
+retry_next_vp:
+			if(vp && next_vp)
+			{
+				const DICT_ATTR *dattr = dict_attrbyname(vp->name);
+				vp = pairfind(vp, dattr->attr);
+			}
 
 
-			vp = find_vp(state->request, this->lhs);
 			/*
 			 *	FIXME: Move sanity checks to
 			 *	post-parse code, so we don't do
@@ -638,6 +649,12 @@
 			int i;
 			regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
 			
+			/* attribute is not in request */
+			if (compare == -1) {
+				rcode = FALSE;
+				break;
+			}
+
 			/*
 			 *	Include substring matches.
 			 */
@@ -646,6 +663,7 @@
 				return FALSE;
 			}
 			rad_assert(data != NULL);
+	
 			rcode = regexec(&reg, data,
 					REQUEST_MAX_REGEX + 1,
 					rxmatch, 0);
@@ -720,6 +738,11 @@
 		} /* switch over comparison operators */
 		break;		/* default from first switch over compare */
 	}
+	if (rcode == FALSE && (vp = vp->next))
+	{
+		next_vp = 1;
+		goto retry_next_vp;
+	}
 
 	/*
 	 *	No trailing &&, ||
@@ -814,6 +837,19 @@
 	case POLICY_LEX_PLUS_EQUALS:
 		operator = T_OP_ADD;
 		break;
+		
+	case POLICY_LEX_MINUS_EQUALS:
+		operator = T_OP_SUB;
+		break;
+		
+	case POLICY_LEX_MINUS_TRUE:
+		operator = T_OP_SUB_ALL; 
+		break;
+		
+	case POLICY_LEX_RX_MINUS:
+		operator = T_OP_SUB_REG;
+		break;
+	
 	
 	default:
 		fprintf(stderr, "Expected '=' for operator, not '%s' at line %d\n",
@@ -898,12 +934,12 @@
 		break;
 
 	case POLICY_LEX_ASSIGN: /* 'union' */
-		pairmove(vps, &head);
+		pairxlatmove(NULL, vps, &head);
 		pairfree(&head);
 		break;
 
 	case POLICY_LEX_CONCAT_EQUALS:
-		pairadd(vps, head);
+		pairxlatmove(NULL, vps, &head);
 		break;
 
 	default:
diff -ur radiusd/src/modules/rlm_policy/parse.c freeradius-1.1.0/src/modules/rlm_policy/parse.c
--- radiusd/src/modules/rlm_policy/parse.c	2005-10-10 06:41:37.000000000 -0400
+++ freeradius-1.1.0/src/modules/rlm_policy/parse.c	2005-10-12 06:46:38.000000000 -0400
@@ -97,6 +97,8 @@
 	{ "!", POLICY_LEX_L_NOT },
 	{ "=", POLICY_LEX_ASSIGN },
 	{ "==", POLICY_LEX_CMP_EQUALS },
+	{ "=*", POLICY_LEX_CMP_TRUE },
+	{ "!*", POLICY_LEX_CMP_FALSE },
 	{ "!=", POLICY_LEX_CMP_NOT_EQUALS },
 	{ "<", POLICY_LEX_LT },
 	{ ">", POLICY_LEX_GT },
@@ -106,6 +108,9 @@
 	{ "!~", POLICY_LEX_RX_NOT_EQUALS },
 	{ ".=", POLICY_LEX_CONCAT_EQUALS },
 	{ ":=", POLICY_LEX_SET_EQUALS },
+	{ "-=", POLICY_LEX_MINUS_EQUALS },
+	{ "-*", POLICY_LEX_MINUS_TRUE },
+	{ "-~", POLICY_LEX_RX_MINUS },
 	{ "double quoted string", POLICY_LEX_DOUBLE_QUOTED_STRING },
 	{ "single quoted string", POLICY_LEX_SINGLE_QUOTED_STRING },
 	{ "back quoted string", POLICY_LEX_BACK_QUOTED_STRING },
@@ -190,6 +195,16 @@
 			*token = POLICY_LEX_MINUS_EQUALS;
 			input++;
 			break;
+			
+		case '*':
+			*token = POLICY_LEX_MINUS_TRUE;
+			input++;
+			break;
+
+		case '~':
+			*token = POLICY_LEX_RX_MINUS;
+			input++;
+			break;
 
 		default:
 			*token = POLICY_LEX_MINUS;
@@ -699,8 +714,8 @@
 					lrad_int2str(rlm_policy_tokens, token, "?"));
 				return 0;
 			}
-			goto check;
 		} /* else it's a comparison? */
+			goto check;
 
 	case POLICY_LEX_DOUBLE_QUOTED_STRING:
 		this->lhs_type = token;
@@ -727,6 +742,8 @@
 		case POLICY_LEX_GT:
 		case POLICY_LEX_LE:
 		case POLICY_LEX_GE:
+		case POLICY_LEX_CMP_TRUE:
+		case POLICY_LEX_CMP_FALSE:
 			break;
 
 		default:
@@ -1231,6 +1248,9 @@
 	case POLICY_LEX_AND_EQUALS:
 	case POLICY_LEX_OR_EQUALS:
 	case POLICY_LEX_PLUS_EQUALS:
+	case POLICY_LEX_MINUS_EQUALS:
+	case POLICY_LEX_MINUS_TRUE:
+	case POLICY_LEX_RX_MINUS:
 		break;
 
 	default:
diff -ur radiusd/src/modules/rlm_policy/rlm_policy.h freeradius-1.1.0/src/modules/rlm_policy/rlm_policy.h
--- radiusd/src/modules/rlm_policy/rlm_policy.h	2005-10-10 06:41:39.000000000 -0400
+++ freeradius-1.1.0/src/modules/rlm_policy/rlm_policy.h	2005-10-12 13:10:15.000000000 -0400
@@ -37,6 +37,7 @@
 
 #include "rad_assert.h"
 
+
 /*
  *	Internal lexer.
  */
@@ -74,6 +75,8 @@
 	POLICY_LEX_OR_EQUALS,	/* |= */
 	POLICY_LEX_PLUS_EQUALS,	/* += */
 	POLICY_LEX_MINUS_EQUALS, /* -= */
+	POLICY_LEX_MINUS_TRUE, /* -* */
+	POLICY_LEX_RX_MINUS, /* -~*/
 	POLICY_LEX_CONCAT_EQUALS, /* .= */
 	POLICY_LEX_VARIABLE,	/* %{foo} */
 	POLICY_LEX_FUNCTION,	/* Hmmm... */
--- radiusd/raddb/policy.txt	2004-12-16 17:21:41.000000000 -0500
+++ freeradius-1.1.0/raddb/policy.txt	2005-10-10 08:19:48.000000000 -0400
@@ -67,5 +67,5 @@
   #
   #  Execute "3pm", as if it was in-line here.
   #
-#  call 3pm
+  3pm()
 }
