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