1 /* $OpenBSD: o_names.c,v 1.20 2015/02/10 11:22:21 jsing Exp $ */ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 6 #include <openssl/opensslconf.h> 7 8 #include <openssl/err.h> 9 #include <openssl/lhash.h> 10 #include <openssl/objects.h> 11 #include <openssl/safestack.h> 12 13 /* I use the ex_data stuff to manage the identifiers for the obj_name_types 14 * that applications may define. I only really use the free function field. 15 */ 16 DECLARE_LHASH_OF(OBJ_NAME); 17 static LHASH_OF(OBJ_NAME) *names_lh = NULL; 18 static int names_type_num = OBJ_NAME_TYPE_NUM; 19 20 typedef struct name_funcs_st { 21 unsigned long (*hash_func)(const char *name); 22 int (*cmp_func)(const char *a, const char *b); 23 void (*free_func)(const char *, int, const char *); 24 } NAME_FUNCS; 25 26 DECLARE_STACK_OF(NAME_FUNCS) 27 28 static STACK_OF(NAME_FUNCS) *name_funcs_stack; 29 30 /* The LHASH callbacks now use the raw "void *" prototypes and do per-variable 31 * casting in the functions. This prevents function pointer casting without the 32 * need for macro-generated wrapper functions. */ 33 34 /* static unsigned long obj_name_hash(OBJ_NAME *a); */ 35 static unsigned long obj_name_hash(const void *a_void); 36 /* static int obj_name_cmp(OBJ_NAME *a,OBJ_NAME *b); */ 37 static int obj_name_cmp(const void *a_void, const void *b_void); 38 39 static IMPLEMENT_LHASH_HASH_FN(obj_name, OBJ_NAME) 40 static IMPLEMENT_LHASH_COMP_FN(obj_name, OBJ_NAME) 41 42 int 43 OBJ_NAME_init(void) 44 { 45 if (names_lh != NULL) 46 return (1); 47 names_lh = lh_OBJ_NAME_new(); 48 return (names_lh != NULL); 49 } 50 51 int 52 OBJ_NAME_new_index(unsigned long (*hash_func)(const char *), 53 int (*cmp_func)(const char *, const char *), 54 void (*free_func)(const char *, int, const char *)) 55 { 56 int ret; 57 int i; 58 NAME_FUNCS *name_funcs; 59 60 if (name_funcs_stack == NULL) 61 name_funcs_stack = sk_NAME_FUNCS_new_null(); 62 if (name_funcs_stack == NULL) 63 return (0); 64 65 ret = names_type_num; 66 names_type_num++; 67 for (i = sk_NAME_FUNCS_num(name_funcs_stack); i < names_type_num; i++) { 68 name_funcs = malloc(sizeof(NAME_FUNCS)); 69 if (!name_funcs) { 70 OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE); 71 return (0); 72 } 73 name_funcs->hash_func = lh_strhash; 74 name_funcs->cmp_func = strcmp; 75 name_funcs->free_func = NULL; 76 if (sk_NAME_FUNCS_push(name_funcs_stack, name_funcs) == 0) { 77 free(name_funcs); 78 OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE); 79 return (0); 80 } 81 } 82 name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret); 83 if (hash_func != NULL) 84 name_funcs->hash_func = hash_func; 85 if (cmp_func != NULL) 86 name_funcs->cmp_func = cmp_func; 87 if (free_func != NULL) 88 name_funcs->free_func = free_func; 89 return (ret); 90 } 91 92 /* static int obj_name_cmp(OBJ_NAME *a, OBJ_NAME *b) */ 93 static int 94 obj_name_cmp(const void *a_void, const void *b_void) 95 { 96 int ret; 97 const OBJ_NAME *a = (const OBJ_NAME *)a_void; 98 const OBJ_NAME *b = (const OBJ_NAME *)b_void; 99 100 ret = a->type - b->type; 101 if (ret == 0) { 102 if ((name_funcs_stack != NULL) && 103 (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) { 104 ret = sk_NAME_FUNCS_value(name_funcs_stack, 105 a->type)->cmp_func(a->name, b->name); 106 } else 107 ret = strcmp(a->name, b->name); 108 } 109 return (ret); 110 } 111 112 /* static unsigned long obj_name_hash(OBJ_NAME *a) */ 113 static unsigned long 114 obj_name_hash(const void *a_void) 115 { 116 unsigned long ret; 117 const OBJ_NAME *a = (const OBJ_NAME *)a_void; 118 119 if ((name_funcs_stack != NULL) && 120 (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) { 121 ret = sk_NAME_FUNCS_value(name_funcs_stack, 122 a->type)->hash_func(a->name); 123 } else { 124 ret = lh_strhash(a->name); 125 } 126 ret ^= a->type; 127 return (ret); 128 } 129 130 const char * 131 OBJ_NAME_get(const char *name, int type) 132 { 133 OBJ_NAME on, *ret; 134 int num = 0, alias; 135 136 if (name == NULL) 137 return (NULL); 138 if ((names_lh == NULL) && !OBJ_NAME_init()) 139 return (NULL); 140 141 alias = type&OBJ_NAME_ALIAS; 142 type&= ~OBJ_NAME_ALIAS; 143 144 on.name = name; 145 on.type = type; 146 147 for (;;) { 148 ret = lh_OBJ_NAME_retrieve(names_lh, &on); 149 if (ret == NULL) 150 return (NULL); 151 if ((ret->alias) && !alias) { 152 if (++num > 10) 153 return (NULL); 154 on.name = ret->data; 155 } else { 156 return (ret->data); 157 } 158 } 159 } 160 161 int 162 OBJ_NAME_add(const char *name, int type, const char *data) 163 { 164 OBJ_NAME *onp, *ret; 165 int alias; 166 167 if ((names_lh == NULL) && !OBJ_NAME_init()) 168 return (0); 169 170 alias = type & OBJ_NAME_ALIAS; 171 type &= ~OBJ_NAME_ALIAS; 172 173 onp = malloc(sizeof(OBJ_NAME)); 174 if (onp == NULL) { 175 /* ERROR */ 176 return (0); 177 } 178 179 onp->name = name; 180 onp->alias = alias; 181 onp->type = type; 182 onp->data = data; 183 184 ret = lh_OBJ_NAME_insert(names_lh, onp); 185 if (ret != NULL) { 186 /* free things */ 187 if ((name_funcs_stack != NULL) && 188 (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) { 189 /* XXX: I'm not sure I understand why the free 190 * function should get three arguments... 191 * -- Richard Levitte 192 */ 193 sk_NAME_FUNCS_value( 194 name_funcs_stack, ret->type)->free_func( 195 ret->name, ret->type, ret->data); 196 } 197 free(ret); 198 } else { 199 if (lh_OBJ_NAME_error(names_lh)) { 200 /* ERROR */ 201 return (0); 202 } 203 } 204 return (1); 205 } 206 207 int 208 OBJ_NAME_remove(const char *name, int type) 209 { 210 OBJ_NAME on, *ret; 211 212 if (names_lh == NULL) 213 return (0); 214 215 type &= ~OBJ_NAME_ALIAS; 216 on.name = name; 217 on.type = type; 218 ret = lh_OBJ_NAME_delete(names_lh, &on); 219 if (ret != NULL) { 220 /* free things */ 221 if ((name_funcs_stack != NULL) && 222 (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) { 223 /* XXX: I'm not sure I understand why the free 224 * function should get three arguments... 225 * -- Richard Levitte 226 */ 227 sk_NAME_FUNCS_value( 228 name_funcs_stack, ret->type)->free_func( 229 ret->name, ret->type, ret->data); 230 } 231 free(ret); 232 return (1); 233 } else 234 return (0); 235 } 236 237 struct doall { 238 int type; 239 void (*fn)(const OBJ_NAME *, void *arg); 240 void *arg; 241 }; 242 243 static void 244 do_all_fn_doall_arg(const OBJ_NAME *name, struct doall *d) 245 { 246 if (name->type == d->type) 247 d->fn(name, d->arg); 248 } 249 250 static IMPLEMENT_LHASH_DOALL_ARG_FN(do_all_fn, const OBJ_NAME, struct doall) 251 252 void 253 OBJ_NAME_do_all(int type, void (*fn)(const OBJ_NAME *, void *arg), void *arg) 254 { 255 struct doall d; 256 257 d.type = type; 258 d.fn = fn; 259 d.arg = arg; 260 261 lh_OBJ_NAME_doall_arg(names_lh, LHASH_DOALL_ARG_FN(do_all_fn), 262 struct doall, &d); 263 } 264 265 struct doall_sorted { 266 int type; 267 int n; 268 const OBJ_NAME **names; 269 }; 270 271 static void 272 do_all_sorted_fn(const OBJ_NAME *name, void *d_) 273 { 274 struct doall_sorted *d = d_; 275 276 if (name->type != d->type) 277 return; 278 279 d->names[d->n++] = name; 280 } 281 282 static int 283 do_all_sorted_cmp(const void *n1_, const void *n2_) 284 { 285 const OBJ_NAME * const *n1 = n1_; 286 const OBJ_NAME * const *n2 = n2_; 287 288 return strcmp((*n1)->name, (*n2)->name); 289 } 290 291 void 292 OBJ_NAME_do_all_sorted(int type, void (*fn)(const OBJ_NAME *, void *arg), 293 void *arg) 294 { 295 struct doall_sorted d; 296 int n; 297 298 d.type = type; 299 d.names = reallocarray(NULL, lh_OBJ_NAME_num_items(names_lh), 300 sizeof *d.names); 301 d.n = 0; 302 if (d.names != NULL) { 303 OBJ_NAME_do_all(type, do_all_sorted_fn, &d); 304 305 qsort((void *)d.names, d.n, sizeof *d.names, do_all_sorted_cmp); 306 307 for (n = 0; n < d.n; ++n) 308 fn(d.names[n], arg); 309 310 free(d.names); 311 } 312 } 313 314 static int free_type; 315 316 static void 317 names_lh_free_doall(OBJ_NAME *onp) 318 { 319 if (onp == NULL) 320 return; 321 322 if (free_type < 0 || free_type == onp->type) 323 OBJ_NAME_remove(onp->name, onp->type); 324 } 325 326 static IMPLEMENT_LHASH_DOALL_FN(names_lh_free, OBJ_NAME) 327 328 static void 329 name_funcs_free(NAME_FUNCS *ptr) 330 { 331 free(ptr); 332 } 333 334 void 335 OBJ_NAME_cleanup(int type) 336 { 337 unsigned long down_load; 338 339 if (names_lh == NULL) 340 return; 341 342 free_type = type; 343 down_load = lh_OBJ_NAME_down_load(names_lh); 344 lh_OBJ_NAME_down_load(names_lh) = 0; 345 346 lh_OBJ_NAME_doall(names_lh, LHASH_DOALL_FN(names_lh_free)); 347 if (type < 0) { 348 lh_OBJ_NAME_free(names_lh); 349 sk_NAME_FUNCS_pop_free(name_funcs_stack, name_funcs_free); 350 names_lh = NULL; 351 name_funcs_stack = NULL; 352 } else 353 lh_OBJ_NAME_down_load(names_lh) = down_load; 354 } 355