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