/* Nessus * Copyright (C) 1998 - 2006 Tenable Network Security, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * as published by the Free Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include "comm.h" #include "utils.h" #include "rules.h" #include "log.h" static char * rules_get_fname(struct arglist *); /* * Returns the name of the rules file */ static char * rules_get_fname(preferences) struct arglist * preferences; { char * t; if((t=arg_get_value(preferences, "rules")))return(t); else return(NESSUSD_RULES); } struct nessus_rules * rules_new(preferences) struct arglist * preferences; { char * filename = rules_get_fname(preferences); struct nessus_rules * nr = emalloc(sizeof(*nr)); FILE * f; nr->rule = RULES_ACCEPT; f = fopen(filename,"w"); if(!f){ perror("rules_new():open "); return nr; } fprintf(f, "#\n# Nessus rules\n#\n\n"); fprintf(f, "# Syntax : accept|reject address/netmask\n"); fprintf(f, "\n# Accept to test anything : \n"); fprintf(f, "default accept\n"); fclose(f); return nr; } int rules_init_aux(rules,file, buffer, len,def) struct nessus_rules * rules; FILE * file; char * buffer; int len; int def; { buffer[0] = buffer[len - 1 ] = '\0'; if(!(fgets(buffer, len - 1, file))){ rules->next = NULL; return def; } else { char *t = buffer; char *v; int t_len; if(t[strlen(t)-1]=='\n')t[strlen(t)-1]='\0'; while((t[0]==' ')||(t[0]=='\t'))t++; if((t[0]=='#')||t[0] == '\0')return rules_init_aux(rules,file, buffer, len,def); v = strchr(t, ' '); if( v == NULL ){ printf("Parse error in the rules file : %s\n", buffer); return rules_init_aux(rules, file, buffer, len, def); } else { if(!strncmp(t, "accept", 6)) rules->rule = RULES_ACCEPT; else if(!strncmp(t, "default", 7)){ if(!strncmp(t+8, "accept", 6))def = RULES_ACCEPT; else def = RULES_REJECT; return rules_init_aux(rules, file, buffer, len, def); } else if((!strncmp(t, "reject", 6))|| (!strncmp(t, "deny", 4)))rules->rule = RULES_REJECT; else { printf("Parse error in the rules file : %s\n", buffer); return rules_init_aux(rules, file, buffer, len,def); } t = v+sizeof(char); v = strchr(t, '/'); if(v)v[0]='\0'; if(t[0]=='!'){ rules->not = 1; t++; } else rules->not = 0; t_len = strlen(t); while(t[t_len-1]==' ') { t[t_len-1]='\0'; t_len --; } if(!(inet_aton(t,&rules->ip))) { if(strcmp(t, "client_ip")) { printf("Parse error in the rules file : '%s' is not a valid IP\n", t); return rules_init_aux(rules, file, buffer, len,def); } else { rules->ip.s_addr = -1; rules->client_ip = 1; } } else rules->client_ip = 0; if(v)rules->mask = atoi(v+sizeof(char)); else rules->mask = 32; if(rules->mask < 0 || rules->mask > 32) { printf("Error in the rules file. %s is not a valid cidr netmask\n", v+sizeof(char)); EXIT(1); } if(rules->mask > 0) { rules->ip.s_addr = ntohl(rules->ip.s_addr) >> (32 - rules->mask); rules->ip.s_addr = htonl(rules->ip.s_addr << (32 - rules->mask)); } else rules->ip.s_addr = 0; rules->next = emalloc(sizeof(*rules)); } } return rules_init_aux(rules->next, file, buffer, len, def); } void rules_init(rules, preferences) struct nessus_rules ** rules; struct arglist * preferences; { struct nessus_rules * nr = emalloc(sizeof(*nr)); char * filename = rules_get_fname(preferences); FILE * f = fopen(filename, "r"); int def = RULES_ACCEPT; char buffer[1024]; if( f == NULL ){ rules_new(preferences); nr->rule = RULES_ACCEPT; nr->next = emalloc(sizeof(*nr)); nr->def = RULES_ACCEPT; *rules = nr; return; } def = rules_init_aux(nr, f, buffer, sizeof(buffer), 0); *rules = nr; rules_set_def(*rules, def); fclose(f); } struct nessus_rules * rules_dup_aux(s, r) struct nessus_rules * s, *r; { printf("rules_dup called - does not work\n"); if(!s->next)return r; else { r->ip.s_addr = s->ip.s_addr; r->mask = s->mask; r->rule = s->rule; r->not = s->not; r->def = s->def; r->next = emalloc(sizeof(*r)); return rules_dup_aux(s->next,r->next); } } struct nessus_rules * rules_dup(struct nessus_rules *s) { struct nessus_rules * r = emalloc(sizeof(*r)); return rules_dup_aux(s, r); } struct nessus_rules * rules_cat(struct nessus_rules * a, struct nessus_rules * b) { struct nessus_rules * s = a; if(a) while(a->next != NULL && a->next->next != NULL) a=a->next; if(a->next){ efree(&a->next); a->next = b; } else { if(a)efree(&a); s = b; } return s; } void rules_set_client_ip(struct nessus_rules * r, struct in_addr client) { if(!r) return; else { if(r->client_ip) r->ip = client; rules_set_client_ip(r->next, client); } } void rules_set_def(struct nessus_rules * r, int def) { if(!r)return; else { r->def = def; rules_set_def(r->next, def); } } void rules_add(struct nessus_rules **rules, struct nessus_rules **user, char * username) { struct nessus_rules * accept_rules = emalloc(sizeof(**rules)); struct nessus_rules * reject_rules = emalloc(sizeof(**rules)); struct nessus_rules * t, *o, *p; int def = (*rules)->def; if(!def)def = RULES_ACCEPT; #ifdef DEBUG_RULES t = *rules; if(t)while(t->next) { printf("DEFAULT: %s/%d\n", inet_ntoa(t->ip), t->mask); t = t->next; } #endif t = *user; o = accept_rules; p = reject_rules; if(t->def == RULES_REJECT)def = RULES_REJECT; if(t != NULL)while(t->next != NULL) { #ifdef DEBUG_RULES printf("rules_add : %d %s/%d\n", t->rule, inet_ntoa(t->ip), t->mask); #endif if(t->rule == RULES_ACCEPT) { if(!username) { accept_rules->ip.s_addr = t->ip.s_addr; accept_rules->client_ip = t->client_ip; accept_rules->mask = t->mask; accept_rules->rule = t->rule; accept_rules->not = t->not; accept_rules->next = emalloc(sizeof(**rules)); accept_rules = accept_rules->next; } else { log_write("user %s : attempted to gain more rights by adding accept %s/%d", username, inet_ntoa(t->ip), t->mask); } } else { reject_rules->ip.s_addr = t->ip.s_addr; reject_rules->client_ip = t->client_ip; reject_rules->mask = t->mask; reject_rules->rule = t->rule; reject_rules->not = t->not; reject_rules->next = emalloc(sizeof(**rules)); reject_rules = reject_rules->next; } t = t->next; } accept_rules = o; reject_rules = p; if(def == RULES_ACCEPT) *rules = rules_cat(rules_cat(reject_rules, *rules),accept_rules); else *rules = rules_cat(reject_rules, rules_cat(*rules, accept_rules)); rules_set_def(*rules, def); #ifdef DEBUG_RULES printf("After rules_cat : \n"); rules_dump(*rules); #endif } #ifdef DEBUG_RULES void rules_dump(struct nessus_rules * rules) { if(!rules->next)return; printf("%d %c%s/%d (def %d)\n", rules->rule, rules->not?'!':' ', inet_ntoa(rules->ip), rules->mask, rules->def); rules_dump(rules->next); } #endif int get_host_rules(struct nessus_rules * rules, struct in_addr addr, int netmask) { struct in_addr backup; if(!rules) { fprintf(stderr, "???? no rules - this is likely to be a bug\n"); fprintf(stderr, "Please report in to bugs@cvs.nessus.org\n"); return RULES_ACCEPT; } if(!rules->next)return rules->def; backup.s_addr = addr.s_addr; if(rules->mask > 0) { addr.s_addr = ntohl(addr.s_addr) >> (32 - rules->mask); addr.s_addr = htonl(addr.s_addr << (32 - rules->mask)); } else addr.s_addr = 0; if(rules->not) { if(addr.s_addr != rules->ip.s_addr)return(rules->rule); } else { if(addr.s_addr == rules->ip.s_addr){ return(rules->rule); } } return get_host_rules(rules->next, backup, netmask); } void rules_free(rules) struct nessus_rules * rules; { while(rules != NULL) { struct nessus_rules * next = rules->next; efree(&rules); rules = next; } }