Refined the rule syntax,moved over to separate rule files and fixed some bugs.
This commit is contained in:
		@ -25,20 +25,17 @@
 | 
				
			|||||||
 * This filter uses "rules" to define the blcking parameters. To configure rules into the configuration file,
 | 
					 * This filter uses "rules" to define the blcking parameters. To configure rules into the configuration file,
 | 
				
			||||||
 * give each rule a unique name and assing the rule contents by passing a string enclosed in quotes.
 | 
					 * give each rule a unique name and assing the rule contents by passing a string enclosed in quotes.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * For example, to define a rule denying users from accessing the column 'salary', the following is needed in the configuration file:
 | 
					 * For example, to define a rule denying users from accessing the column 'salary' between 15:00 and 17:00, the following is needed in the configuration file:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *		rule1="rule block_salary deny columns salary"
 | 
					 *		rule1="rule block_salary deny columns salary at_times 15:00:00-17:00:00"
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * To apply this rule to users John, connecting from any address, and Jane, connecting from the address 192.168.0.1, use the following:
 | 
					 * To apply this rule to users John, connecting from any address, and Jane, connecting from the address 192.168.0.1, use the following:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *		rule2="users John@% Jane@192.168.0.1 rules block_salary"
 | 
					 *		rule2="users John@% Jane@192.168.0.1 match any rules block_salary"
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Rule syntax TODO: implement timeranges, query type restrictions
 | 
					 * Rule syntax TODO: query type restrictions
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * rule NAME deny|allow|require
 | 
					 * rule NAME deny|allow [wildcard | columns VALUE ... | regex REGEX] [at_times VALUE...]
 | 
				
			||||||
 *				[wildcard|columns VALUE ...]
 | 
					 | 
				
			||||||
 *				[times VALUE...]
 | 
					 | 
				
			||||||
 *				[on_queries [all|select|update|delete|insert]...]
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#include <my_config.h>
 | 
					#include <my_config.h>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
@ -432,7 +429,9 @@ char* next_ip_class(char* str)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	if(ptr == str){
 | 
						if(ptr == str){
 | 
				
			||||||
		return NULL;
 | 
							*ptr++ = '%';
 | 
				
			||||||
 | 
							*ptr = '\0';
 | 
				
			||||||
 | 
							return str;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*++ptr = '%';
 | 
						*++ptr = '%';
 | 
				
			||||||
@ -751,7 +750,7 @@ void link_rules(char* rule, FW_INSTANCE* instance)
 | 
				
			|||||||
			user->name = strdup(userptr);
 | 
								user->name = strdup(userptr);
 | 
				
			||||||
			tl = rlistdup(rulelist);
 | 
								tl = rlistdup(rulelist);
 | 
				
			||||||
			tail = tl;
 | 
								tail = tl;
 | 
				
			||||||
			while(tail->next){
 | 
								while(tail && tail->next){
 | 
				
			||||||
				tail = tail->next;
 | 
									tail = tail->next;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -797,6 +796,7 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
 | 
				
			|||||||
		rlist = (RULELIST*)calloc(1,sizeof(RULELIST));
 | 
							rlist = (RULELIST*)calloc(1,sizeof(RULELIST));
 | 
				
			||||||
		ruledef->name = strdup(tok);
 | 
							ruledef->name = strdup(tok);
 | 
				
			||||||
		ruledef->type = RT_UNDEFINED;
 | 
							ruledef->type = RT_UNDEFINED;
 | 
				
			||||||
 | 
							ruledef->on_queries = ALL;
 | 
				
			||||||
		rlist->rule = ruledef;
 | 
							rlist->rule = ruledef;
 | 
				
			||||||
		rlist->next = instance->rules;
 | 
							rlist->next = instance->rules;
 | 
				
			||||||
		instance->rules = rlist;
 | 
							instance->rules = rlist;
 | 
				
			||||||
@ -830,7 +830,7 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
 | 
				
			|||||||
				STRLINK *tail = NULL,*current;
 | 
									STRLINK *tail = NULL,*current;
 | 
				
			||||||
				ruledef->type = RT_COLUMN;
 | 
									ruledef->type = RT_COLUMN;
 | 
				
			||||||
				tok = strtok(NULL, " ,");
 | 
									tok = strtok(NULL, " ,");
 | 
				
			||||||
				while(tok && strcmp(tok,"times") != 0){
 | 
									while(tok && strcmp(tok,"at_times") != 0){
 | 
				
			||||||
					current = malloc(sizeof(STRLINK));
 | 
										current = malloc(sizeof(STRLINK));
 | 
				
			||||||
					current->value = strdup(tok);
 | 
										current->value = strdup(tok);
 | 
				
			||||||
					current->next = tail;
 | 
										current->next = tail;
 | 
				
			||||||
@ -842,15 +842,20 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
 | 
				
			|||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		else if(strcmp(tok,"times") == 0)
 | 
							else if(strcmp(tok,"at_times") == 0)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				tok = strtok(NULL, " ,");
 | 
									tok = strtok(NULL, " ,");
 | 
				
			||||||
 | 
									TIMERANGE *tr = NULL;
 | 
				
			||||||
				TIMERANGE *tr = parse_time(tok,instance);
 | 
									while(tok){
 | 
				
			||||||
 | 
										TIMERANGE *tmp = parse_time(tok,instance);
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
				if(IS_RVRS_TIME(tr)){
 | 
										if(IS_RVRS_TIME(tmp)){
 | 
				
			||||||
					tr = split_reverse_time(tr);
 | 
											tmp = split_reverse_time(tmp);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										tmp->next = tr;
 | 
				
			||||||
 | 
										tr = tmp;
 | 
				
			||||||
 | 
										tok = strtok(NULL, " ,");
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				ruledef->active = tr;
 | 
									ruledef->active = tr;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -873,8 +878,9 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				str = malloc(((tok - start) + 1)*sizeof(char));
 | 
									str = malloc(((tok - start) + 1)*sizeof(char));
 | 
				
			||||||
				*tok = '\0';
 | 
					
 | 
				
			||||||
				memcpy(str, start, (tok-start) + 1);
 | 
									memcpy(str, start, (tok-start));
 | 
				
			||||||
 | 
									memset((str + (tok-start) +1),0,1);
 | 
				
			||||||
			    
 | 
								    
 | 
				
			||||||
				regex_t *re = malloc(sizeof(regex_t));
 | 
									regex_t *re = malloc(sizeof(regex_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -911,16 +917,19 @@ static	FILTER	*
 | 
				
			|||||||
createInstance(char **options, FILTER_PARAMETER **params)
 | 
					createInstance(char **options, FILTER_PARAMETER **params)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	FW_INSTANCE	*my_instance;
 | 
						FW_INSTANCE	*my_instance;
 | 
				
			||||||
  
 | 
					  	int i,paramc;
 | 
				
			||||||
 | 
						HASHTABLE* ht;
 | 
				
			||||||
 | 
						STRLINK *ptr,*tmp;
 | 
				
			||||||
 | 
						char *filename, *nl;
 | 
				
			||||||
 | 
						char buffer[2048];
 | 
				
			||||||
 | 
						FILE* file;
 | 
				
			||||||
	if ((my_instance = calloc(1, sizeof(FW_INSTANCE))) == NULL){
 | 
						if ((my_instance = calloc(1, sizeof(FW_INSTANCE))) == NULL){
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
	HASHTABLE* ht;
 | 
					 | 
				
			||||||
	STRLINK *ptr,*tmp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if((ht = hashtable_alloc(7, hashkeyfun, hashcmpfun)) == NULL){
 | 
						if((ht = hashtable_alloc(7, hashkeyfun, hashcmpfun)) == NULL){
 | 
				
			||||||
		skygw_log_write(LOGFILE_ERROR, "Unable to allocate hashtable.");
 | 
							skygw_log_write(LOGFILE_ERROR, "Unable to allocate hashtable.");
 | 
				
			||||||
 | 
							free(my_instance);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -930,14 +939,37 @@ createInstance(char **options, FILTER_PARAMETER **params)
 | 
				
			|||||||
	my_instance->def_op = true;
 | 
						my_instance->def_op = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for(i = 0;params[i];i++){
 | 
						for(i = 0;params[i];i++){
 | 
				
			||||||
		if(strstr(params[i]->name,"rule")){
 | 
							if(strcmp(params[i]->name, "rulelist") == 0){
 | 
				
			||||||
			parse_rule(params[i]->value,my_instance);
 | 
								filename = strdup(params[i]->value);
 | 
				
			||||||
		}else if(strcmp(params[i]->name,"mode") == 0 && 
 | 
					 | 
				
			||||||
				 strcmp(params[i]->value,"whitelist") == 0){
 | 
					 | 
				
			||||||
			my_instance->def_op = false;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if((file = fopen(filename,"rb")) == NULL ){
 | 
				
			||||||
 | 
							free(my_instance);
 | 
				
			||||||
 | 
							free(filename);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free(filename);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						while(!feof(file))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(fgets(buffer,2048,file) == NULL){
 | 
				
			||||||
 | 
									free(my_instance);
 | 
				
			||||||
 | 
									return NULL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if((nl = strchr(buffer,'\n')) != NULL && ((char*)nl - (char*)buffer) < 2048){
 | 
				
			||||||
 | 
									*nl = '\0';
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								parse_rule(buffer,my_instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fclose(file);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	/**Apply the rules to users*/
 | 
						/**Apply the rules to users*/
 | 
				
			||||||
	ptr = my_instance->userstrings;
 | 
						ptr = my_instance->userstrings;
 | 
				
			||||||
	while(ptr){
 | 
						while(ptr){
 | 
				
			||||||
@ -1148,6 +1180,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
 | 
				
			|||||||
	FW_SESSION	*my_session = (FW_SESSION *)session;
 | 
						FW_SESSION	*my_session = (FW_SESSION *)session;
 | 
				
			||||||
	FW_INSTANCE	*my_instance = (FW_INSTANCE *)instance;
 | 
						FW_INSTANCE	*my_instance = (FW_INSTANCE *)instance;
 | 
				
			||||||
	time_t time_now;
 | 
						time_t time_now;
 | 
				
			||||||
 | 
						struct tm* tm_now; 
 | 
				
			||||||
	bool accept = my_instance->def_op,
 | 
						bool accept = my_instance->def_op,
 | 
				
			||||||
		is_sql = false,
 | 
							is_sql = false,
 | 
				
			||||||
		is_real = false,rule_match;
 | 
							is_real = false,rule_match;
 | 
				
			||||||
@ -1164,6 +1197,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
 | 
				
			|||||||
	sprintf(uname_addr,"%s@%s",dcb->user,ipaddr);
 | 
						sprintf(uname_addr,"%s@%s",dcb->user,ipaddr);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	time(&time_now);
 | 
						time(&time_now);
 | 
				
			||||||
 | 
						tm_now = localtime(&time_now);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if((user = (USER*)hashtable_fetch(my_instance->htable, uname_addr)) == NULL){
 | 
						if((user = (USER*)hashtable_fetch(my_instance->htable, uname_addr)) == NULL){
 | 
				
			||||||
			while(user == NULL && next_ip_class(ipaddr)){
 | 
								while(user == NULL && next_ip_class(ipaddr)){
 | 
				
			||||||
@ -1216,6 +1250,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
 | 
				
			|||||||
		switch(rulelist->rule->type){
 | 
							switch(rulelist->rule->type){
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
		case RT_UNDEFINED:
 | 
							case RT_UNDEFINED:
 | 
				
			||||||
 | 
								skygw_log_write_flush(LOGFILE_ERROR, "Error: Undefined rule type found.");	
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
		case RT_REGEX:
 | 
							case RT_REGEX:
 | 
				
			||||||
@ -1226,6 +1261,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
 | 
				
			|||||||
				
 | 
									
 | 
				
			||||||
				if(!rulelist->rule->allow){
 | 
									if(!rulelist->rule->allow){
 | 
				
			||||||
					msg = strdup("Permission denied, query matched regular expression.");
 | 
										msg = strdup("Permission denied, query matched regular expression.");
 | 
				
			||||||
 | 
										skygw_log_write(LOGFILE_TRACE, "fwfilter: rule '%s': regex matched on query",rulelist->rule->name);	
 | 
				
			||||||
					goto queryresolved;
 | 
										goto queryresolved;
 | 
				
			||||||
				}else{
 | 
									}else{
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
@ -1238,6 +1274,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
 | 
				
			|||||||
			if(!rulelist->rule->allow){
 | 
								if(!rulelist->rule->allow){
 | 
				
			||||||
				accept = false;
 | 
									accept = false;
 | 
				
			||||||
				msg = strdup("Permission denied at this time.");
 | 
									msg = strdup("Permission denied at this time.");
 | 
				
			||||||
 | 
									skygw_log_write(LOGFILE_TRACE, "fwfilter: rule '%s': query denied at: %s",rulelist->rule->name,asctime(tm_now));	
 | 
				
			||||||
				goto queryresolved;
 | 
									goto queryresolved;
 | 
				
			||||||
			}else{
 | 
								}else{
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
@ -1260,6 +1297,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
							if(!rulelist->rule->allow){
 | 
												if(!rulelist->rule->allow){
 | 
				
			||||||
								sprintf(emsg,"Permission denied to column '%s'.",strln->value);
 | 
													sprintf(emsg,"Permission denied to column '%s'.",strln->value);
 | 
				
			||||||
 | 
													skygw_log_write(LOGFILE_TRACE, "fwfilter: rule '%s': query targets forbidden column: %s",rulelist->rule->name,strln->value);	
 | 
				
			||||||
								msg = strdup(emsg);
 | 
													msg = strdup(emsg);
 | 
				
			||||||
								goto queryresolved;
 | 
													goto queryresolved;
 | 
				
			||||||
							}else{
 | 
												}else{
 | 
				
			||||||
@ -1287,6 +1325,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
						if(!rulelist->rule->allow){
 | 
											if(!rulelist->rule->allow){
 | 
				
			||||||
							msg = strdup("Usage of wildcard denied.");
 | 
												msg = strdup("Usage of wildcard denied.");
 | 
				
			||||||
 | 
												skygw_log_write(LOGFILE_TRACE, "fwfilter: rule '%s': query contains a wildcard.",rulelist->rule->name);	
 | 
				
			||||||
							goto queryresolved;
 | 
												goto queryresolved;
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
@ -1295,6 +1334,9 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
 | 
				
			|||||||
			
 | 
								
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		rulelist = rulelist->next;
 | 
							rulelist = rulelist->next;
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user