1 /* $NetBSD: npf_var.c,v 1.9 2015/07/12 23:54:44 rmind Exp $ */ 2 3 /*- 4 * Copyright (c) 2011-2012 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __RCSID("$NetBSD: npf_var.c,v 1.9 2015/07/12 23:54:44 rmind Exp $"); 34 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 #define _NPFVAR_PRIVATE 40 #include "npfctl.h" 41 42 typedef struct npf_element { 43 void * e_data; 44 int e_type; 45 struct npf_element *e_next; 46 } npf_element_t; 47 48 struct npfvar { 49 char * v_key; 50 npf_element_t * v_elements; 51 npf_element_t * v_last; 52 int v_type; 53 size_t v_count; 54 void * v_next; 55 }; 56 57 static npfvar_t * var_list = NULL; 58 static size_t var_num = 0; 59 60 npfvar_t * 61 npfvar_create(void) 62 { 63 npfvar_t *vp = ecalloc(1, sizeof(*vp)); 64 var_num++; 65 return vp; 66 } 67 68 npfvar_t * 69 npfvar_lookup(const char *key) 70 { 71 for (npfvar_t *it = var_list; it != NULL; it = it->v_next) 72 if (strcmp(it->v_key, key) == 0) 73 return it; 74 return NULL; 75 } 76 77 const char * 78 npfvar_type(size_t t) 79 { 80 if (t >= __arraycount(npfvar_types)) { 81 return "unknown"; 82 } 83 return npfvar_types[t]; 84 } 85 86 void 87 npfvar_add(npfvar_t *vp, const char *name) 88 { 89 vp->v_key = estrdup(name); 90 vp->v_next = var_list; 91 var_list = vp; 92 } 93 94 npfvar_t * 95 npfvar_create_element(int type, const void *data, size_t len) 96 { 97 npfvar_t *vp = npfvar_create(); 98 return npfvar_add_element(vp, type, data, len); 99 } 100 101 npfvar_t * 102 npfvar_create_from_string(int type, const char *string) 103 { 104 return npfvar_create_element(type, string, strlen(string) + 1); 105 } 106 107 npfvar_t * 108 npfvar_add_element(npfvar_t *vp, int type, const void *data, size_t len) 109 { 110 npf_element_t *el; 111 112 if (vp->v_count == 0) { 113 vp->v_type = type; 114 } else if (NPFVAR_TYPE(vp->v_type) != NPFVAR_TYPE(type)) { 115 yyerror("element type '%s' does not match variable type '%s'", 116 npfvar_type(type), npfvar_type(vp->v_type)); 117 return NULL; 118 } 119 vp->v_count++; 120 el = ecalloc(1, sizeof(*el)); 121 el->e_data = ecalloc(1, len); 122 el->e_type = type; 123 memcpy(el->e_data, data, len); 124 125 /* Preserve order of insertion. */ 126 if (vp->v_elements == NULL) { 127 vp->v_elements = el; 128 } else { 129 vp->v_last->e_next = el; 130 } 131 vp->v_last = el; 132 return vp; 133 } 134 135 npfvar_t * 136 npfvar_add_elements(npfvar_t *vp, npfvar_t *vp2) 137 { 138 if (vp2 == NULL) 139 return vp; 140 if (vp == NULL) 141 return vp2; 142 143 if (vp->v_elements == NULL) { 144 if (vp2->v_elements) { 145 vp->v_type = vp2->v_type; 146 vp->v_elements = vp2->v_elements; 147 } 148 } else if (vp2->v_elements) { 149 if (NPFVAR_TYPE(vp->v_type) != NPFVAR_TYPE(vp2->v_type)) { 150 yyerror("variable '%s' type '%s' does not match " 151 "variable '%s' type '%s'", vp->v_key, 152 npfvar_type(vp->v_type), 153 vp2->v_key, npfvar_type(vp2->v_type)); 154 return NULL; 155 } 156 vp->v_last->e_next = vp2->v_elements; 157 } 158 if (vp2->v_elements) { 159 vp->v_last = vp2->v_last; 160 vp->v_count += vp2->v_count; 161 vp2->v_elements = NULL; 162 vp2->v_count = 0; 163 vp2->v_last = NULL; 164 } 165 npfvar_destroy(vp2); 166 return vp; 167 } 168 169 static void 170 npfvar_free_elements(npf_element_t *el) 171 { 172 if (el == NULL) 173 return; 174 npfvar_free_elements(el->e_next); 175 free(el->e_data); 176 free(el); 177 } 178 179 void 180 npfvar_destroy(npfvar_t *vp) 181 { 182 npfvar_free_elements(vp->v_elements); 183 free(vp->v_key); 184 free(vp); 185 var_num--; 186 } 187 188 char * 189 npfvar_expand_string(const npfvar_t *vp) 190 { 191 return npfvar_get_data(vp, NPFVAR_STRING, 0); 192 } 193 194 size_t 195 npfvar_get_count(const npfvar_t *vp) 196 { 197 return vp ? vp->v_count : 0; 198 } 199 200 static void * 201 npfvar_get_data1(const npfvar_t *vp, int type, size_t idx, size_t level) 202 { 203 npf_element_t *el; 204 205 if (level >= var_num) { 206 yyerror("variable loop for '%s'", vp->v_key); 207 return NULL; 208 } 209 210 if (vp == NULL) 211 return NULL; 212 213 if (NPFVAR_TYPE(vp->v_type) != NPFVAR_TYPE(type)) { 214 yyerror("variable '%s' is of type '%s' not '%s'", vp->v_key, 215 npfvar_type(vp->v_type), npfvar_type(type)); 216 return NULL; 217 } 218 219 if (vp->v_count <= idx) { 220 yyerror("variable '%s' has only %zu elements, requested %zu", 221 vp->v_key, vp->v_count, idx); 222 return NULL; 223 } 224 225 el = vp->v_elements; 226 while (idx--) { 227 el = el->e_next; 228 } 229 230 if (vp->v_type == NPFVAR_VAR_ID) { 231 npfvar_t *rvp = npfvar_lookup(el->e_data); 232 return npfvar_get_data1(rvp, type, 0, level + 1); 233 } 234 return el->e_data; 235 } 236 237 static int 238 npfvar_get_type1(const npfvar_t *vp, size_t idx, size_t level) 239 { 240 npf_element_t *el; 241 242 if (vp == NULL) 243 return -1; 244 245 if (level >= var_num) { 246 yyerror("variable loop for '%s'", vp->v_key); 247 return -1; 248 } 249 250 if (vp->v_count <= idx) { 251 yyerror("variable '%s' has only %zu elements, requested %zu", 252 vp->v_key, vp->v_count, idx); 253 return -1; 254 } 255 256 el = vp->v_elements; 257 while (idx--) { 258 el = el->e_next; 259 } 260 261 if (vp->v_type == NPFVAR_VAR_ID) { 262 npfvar_t *rvp = npfvar_lookup(el->e_data); 263 return npfvar_get_type1(rvp, 0, level + 1); 264 } 265 return el->e_type; 266 } 267 268 int 269 npfvar_get_type(const npfvar_t *vp, size_t idx) 270 { 271 return npfvar_get_type1(vp, idx, 0); 272 } 273 274 void * 275 npfvar_get_data(const npfvar_t *vp, int type, size_t idx) 276 { 277 return npfvar_get_data1(vp, type, idx, 0); 278 } 279