1/* $Id: options.c,v 1.28 2013/12/13 14:07:08 nanard Exp $ */ 2/* MiniUPnP project 3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ 4 * author: Ryan Wagoner 5 * (c) 2006-2014 Thomas Bernard 6 * This software is subject to the conditions detailed 7 * in the LICENCE file provided within the distribution */ 8 9#include <stdio.h> 10#include <string.h> 11#include <stdlib.h> 12#include <ctype.h> 13#include <syslog.h> 14#include "config.h" 15#include "options.h" 16#include "upnppermissions.h" 17#ifdef PCP_SADSCP 18#include "pcplearndscp.h" 19#endif /* PCP_SADSPC */ 20#include "upnpglobalvars.h" 21 22#ifndef DISABLE_CONFIG_FILE 23struct option * ary_options = NULL; 24static char * string_repo = NULL; 25unsigned int num_options = 0; 26 27static const struct { 28 enum upnpconfigoptions id; 29 const char * name; 30} optionids[] = { 31 { UPNPEXT_IFNAME, "ext_ifname" }, 32 { UPNPEXT_IP, "ext_ip" }, 33 { UPNPLISTENING_IP, "listening_ip" }, 34#ifdef ENABLE_IPV6 35 { UPNPIPV6_LISTENING_IP, "ipv6_listening_ip" }, 36#endif /* ENABLE_IPV6 */ 37 { UPNPPORT, "port" }, 38 { UPNPPORT, "http_port" }, /* "port" and "http_port" are synonims */ 39#ifdef ENABLE_HTTPS 40 { UPNPHTTPSPORT, "https_port" }, 41#endif /* ENABLE_HTTPS */ 42 { UPNPBITRATE_UP, "bitrate_up" }, 43 { UPNPBITRATE_DOWN, "bitrate_down" }, 44 { UPNPPRESENTATIONURL, "presentation_url" }, 45#ifdef ENABLE_MANUFACTURER_INFO_CONFIGURATION 46 { UPNPFRIENDLY_NAME, "friendly_name" }, 47 { UPNPMANUFACTURER_NAME, "manufacturer_name" }, 48 { UPNPMANUFACTURER_URL, "manufacturer_url" }, 49 { UPNPMODEL_NAME, "model_name" }, 50 { UPNPMODEL_DESCRIPTION, "model_description" }, 51 { UPNPMODEL_URL, "model_url" }, 52#endif 53 { UPNPNOTIFY_INTERVAL, "notify_interval" }, 54 { UPNPSYSTEM_UPTIME, "system_uptime" }, 55 { UPNPPACKET_LOG, "packet_log" }, 56 { UPNPUUID, "uuid"}, 57 { UPNPSERIAL, "serial"}, 58 { UPNPMODEL_NUMBER, "model_number"}, 59 { UPNPCLEANTHRESHOLD, "clean_ruleset_threshold"}, 60 { UPNPCLEANINTERVAL, "clean_ruleset_interval"}, 61#ifdef USE_NETFILTER 62 { UPNPFORWARDCHAIN, "upnp_forward_chain"}, 63 { UPNPNATCHAIN, "upnp_nat_chain"}, 64#endif 65#ifdef ENABLE_NATPMP 66 { UPNPENABLENATPMP, "enable_natpmp"}, 67#endif 68#ifdef ENABLE_PCP 69 { UPNPPCPMINLIFETIME, "min_lifetime"}, 70 { UPNPPCPMAXLIFETIME, "max_lifetime"}, 71 { UPNPPCPALLOWTHIRDPARTY, "pcp_allow_thirdparty"}, 72#endif 73 { UPNPENABLE, "enable_upnp"}, 74#ifdef USE_PF 75 { UPNPANCHOR, "anchor"}, 76 { UPNPQUEUE, "queue"}, 77 { UPNPTAG, "tag"}, 78#endif 79#ifdef PF_ENABLE_FILTER_RULES 80 { UPNPQUICKRULES, "quickrules" }, 81#endif 82#ifdef ENABLE_LEASEFILE 83 { UPNPLEASEFILE, "lease_file"}, 84#endif 85 { UPNPMINISSDPDSOCKET, "minissdpdsocket"}, 86 { UPNPSECUREMODE, "secure_mode"} 87}; 88 89int 90readoptionsfile(const char * fname) 91{ 92 FILE *hfile = NULL; 93 char buffer[1024]; 94 char *equals; 95 char *name; 96 char *value; 97 char *t; 98 int linenum = 0; 99 unsigned int i; 100 enum upnpconfigoptions id; 101 size_t string_repo_len = 0; 102 size_t len; 103 void *tmp; 104 105 if(!fname || (strlen(fname) == 0)) 106 return -1; 107 108 memset(buffer, 0, sizeof(buffer)); 109 110#ifdef DEBUG 111 printf("Reading configuration from file %s\n", fname); 112#endif 113 114 if(!(hfile = fopen(fname, "r"))) 115 return -1; 116 117 if(ary_options != NULL) 118 { 119 free(ary_options); 120 num_options = 0; 121 } 122 123 while(fgets(buffer, sizeof(buffer), hfile)) 124 { 125 linenum++; 126 t = strchr(buffer, '\n'); 127 if(t) 128 { 129 *t = '\0'; 130 t--; 131 /* remove spaces at the end of the line */ 132 while((t >= buffer) && isspace(*t)) 133 { 134 *t = '\0'; 135 t--; 136 } 137 } 138 139 /* skip leading whitespaces */ 140 name = buffer; 141 while(isspace(*name)) 142 name++; 143 144 /* check for comments or empty lines */ 145 if(name[0] == '#' || name[0] == '\0') continue; 146 147 len = strlen(name); /* length of the whole line excluding leading 148 * and ending white spaces */ 149 /* check for UPnP permissions rule */ 150 if((len > 6) && (0 == memcmp(name, "allow", 5) || 0 == memcmp(name, "deny", 4))) 151 { 152 tmp = realloc(upnppermlist, sizeof(struct upnpperm) * (num_upnpperm+1)); 153 if(tmp == NULL) 154 { 155 fprintf(stderr, "memory allocation error. Permission line in file %s line %d\n", 156 fname, linenum); 157 } 158 else 159 { 160 upnppermlist = tmp; 161 /* parse the rule */ 162 if(read_permission_line(upnppermlist + num_upnpperm, name) >= 0) 163 { 164 num_upnpperm++; 165 } 166 else 167 { 168 fprintf(stderr, "parsing error file %s line %d : %s\n", 169 fname, linenum, name); 170 } 171 } 172 continue; 173 } 174#ifdef PCP_SADSCP 175 /* check for DSCP values configuration */ 176 if((len > 15) && 0 == memcmp(name, "set_learn_dscp", sizeof("set_learn_dscp")-1) ) 177 { 178 tmp = realloc(dscp_values_list, sizeof(struct dscp_values) * (num_dscp_values+1)); 179 if(tmp == NULL) 180 { 181 fprintf(stderr, "memory allocation error. DSCP line in file %s line %d\n", 182 fname, linenum); 183 } 184 else 185 { 186 dscp_values_list = tmp; 187 /* parse the rule */ 188 if(read_learn_dscp_line(dscp_values_list + num_dscp_values, name) >= 0) 189 { 190 num_dscp_values++; 191 } 192 else 193 { 194 fprintf(stderr, "parsing error file %s line %d : %s\n", 195 fname, linenum, name); 196 } 197 } 198 continue; 199 } 200#endif /* PCP_SADSCP */ 201 if(!(equals = strchr(name, '='))) 202 { 203 fprintf(stderr, "parsing error file %s line %d : %s\n", 204 fname, linenum, name); 205 continue; 206 } 207 208 /* remove ending whitespaces */ 209 for(t=equals-1; t>name && isspace(*t); t--) 210 *t = '\0'; 211 212 *equals = '\0'; 213 value = equals+1; 214 215 /* skip leading whitespaces */ 216 while(isspace(*value)) 217 value++; 218 219 id = UPNP_INVALID; 220 for(i=0; i<sizeof(optionids)/sizeof(optionids[0]); i++) 221 { 222 /*printf("%2d %2d %s %s\n", i, optionids[i].id, name, 223 optionids[i].name); */ 224 225 if(0 == strcmp(name, optionids[i].name)) 226 { 227 id = optionids[i].id; 228 break; 229 } 230 } 231 232 if(id == UPNP_INVALID) 233 { 234 fprintf(stderr, "invalid option in file %s line %d : %s=%s\n", 235 fname, linenum, name, value); 236 } 237 else 238 { 239 tmp = realloc(ary_options, (num_options + 1) * sizeof(struct option)); 240 if(tmp == NULL) 241 { 242 fprintf(stderr, "memory allocation error. Option in file %s line %d.\n", 243 fname, linenum); 244 } 245 else 246 { 247 ary_options = tmp; 248 len = strlen(value) + 1; /* +1 for terminating '\0' */ 249 tmp = realloc(string_repo, string_repo_len + len); 250 if(tmp == NULL) 251 { 252 fprintf(stderr, "memory allocation error, Option value in file %s line %d : %s=%s\n", 253 fname, linenum, name, value); 254 } 255 else 256 { 257 string_repo = tmp; 258 memcpy(string_repo + string_repo_len, value, len); 259 ary_options[num_options].id = id; 260 /* save the offset instead of the absolute address because realloc() could 261 * change it */ 262 ary_options[num_options].value = (const char *)string_repo_len; 263 num_options += 1; 264 string_repo_len += len; 265 } 266 } 267 } 268 269 } 270 271 fclose(hfile); 272 273 for(i = 0; i < num_options; i++) 274 { 275 /* add start address of string_repo to get right pointer */ 276 ary_options[i].value = string_repo + (size_t)ary_options[i].value; 277 } 278 279 return 0; 280} 281 282void 283freeoptions(void) 284{ 285 if(ary_options) 286 { 287 free(ary_options); 288 ary_options = NULL; 289 num_options = 0; 290 } 291 if(string_repo) 292 { 293 free(string_repo); 294 string_repo = NULL; 295 } 296 if(upnppermlist) 297 { 298 free(upnppermlist); 299 upnppermlist = NULL; 300 num_upnpperm = 0; 301 } 302#ifdef PCP_SADSCP 303 if(dscp_values_list) 304 { 305 unsigned int i; 306 for (i = 0; i < num_dscp_values; i++) { 307 if (dscp_values_list[i].app_name) { 308 free(dscp_values_list[i].app_name); 309 dscp_values_list[i].app_name = NULL; 310 } 311 } 312 free(dscp_values_list); 313 dscp_values_list = NULL; 314 num_dscp_values = 0; 315 } 316#endif /* PCP_SADSCP */ 317} 318 319#endif /* DISABLE_CONFIG_FILE */ 320