/* * Simple memory cache for ini file parser * * This should be copied from somewhere but, unfortunately is reinvented. * * Copyright (C) 2019 James.Bottomley@HansenPartnership.com * * SPDX-License-Identifier: LGPL-2.1-only */ #include #include #include #include #include "openssl-pkcs11.h" struct kv { const char *key; const char *value; int len; }; struct s_s { const char *section; struct kv *kvs; int kv_count; }; static struct s_s *s = NULL; static int section_count = 0; static struct s_s *section_get(const char *section) { int i; for (i = 0; i < section_count; i++) if (strcmp(s[i].section, section) == 0) return &s[i]; return NULL; } static void remove_section(int sn) { section_count--; /* last entry, just keep the reduced count (realloc will cope) */ if (sn == section_count) { return; } /* just move everything over it and reduce the section count */ memcpy(&s[sn], &s[sn + 1], sizeof(struct s_s)*(section_count - sn)); } static struct s_s *section_get_alloc(const char *section) { struct s_s *s_s = section_get(section); if (s_s) return s_s; s = reallocarray(s, section_count + 1, sizeof(*s_s)); if (!s) { fprintf(stderr, "realloc of section %s failed: %s", section, strerror(errno)); return NULL; } s_s = &s[section_count++]; memset(s_s, 0, sizeof(*s_s)); s_s->section = section; return s_s; } static struct kv *kv_get(struct s_s *s_s, const char *key) { int i; for (i = 0; i < s_s->kv_count; i++) if (strcmp(s_s->kvs[i].key, key) == 0) return &s_s->kvs[i]; return NULL; } static struct kv *kv_get_alloc(struct s_s *s_s, const char *key) { struct kv *kv = kv_get(s_s, key); if (kv) return kv; s_s->kvs = reallocarray(s_s->kvs, s_s->kv_count + 1, sizeof(*kv)); if (!s) { fprintf(stderr, "realloc of section %s kvs failed: %s", s_s->section, strerror(errno)); return NULL; } kv = &s_s->kvs[s_s->kv_count++]; memset(kv, 0, sizeof(*kv)); kv->key = key; return kv; } static void cache_add_internal(struct s_s *s_s, const char *key, const char *value, int len) { struct kv *kv = kv_get_alloc(s_s, key); if (!kv) return; if (kv->value && kv->len == CACHE_PKEY) /* discard const */ crypto_cache_free_pkey((void *)kv->value); if (len == 0) len = strlen(value); kv->value = value; kv->len = len; } void cache_add(const char *section, const char *key, const char *value, int len) { struct s_s *s_s = section_get_alloc(section); if (!s_s) return; cache_add_internal(s_s, key, value, len); } void cache_add_by_secnum(int sec_num, const char *key, const char *value, int len) { struct s_s *s_s; if (sec_num > section_count) return; s_s = &s[sec_num]; cache_add_internal(s_s, key, value, len); } static const char * cache_get_internal(struct s_s *sec, const char *key, int *len) { struct kv *kv; kv = kv_get(sec, key); if (!kv) return NULL; if (len) *len = kv->len; return kv->value; } const char *cache_get(const char *section, const char *key, int *len) { struct s_s *sec = section_get(section); if (!sec) return NULL; return cache_get_internal(sec, key, len); } const char *cache_get_by_secnum(int sec_num, const char *key, int *len) { struct s_s *sec; if (sec_num >= section_count) return NULL; sec = &s[sec_num]; return cache_get_internal(sec, key, len); } const char *cache_get_section(int sc) { if (sc >= section_count) return NULL; return s[sc].section; } int cache_get_sections(void) { return section_count; } void cache_load_crypto_keys(void) { int i; /* every section apart from global must have public key and a * private key */ for (i = 1; i < section_count; i++) { struct kv *kv; int ret; kv = kv_get(&s[i], INI_PUBLIC_KEY); if (!kv) { kv = kv_get(&s[i], INI_CERT); if (kv) ret = crypto_load_cert(i, kv->value); } else { ret = crypto_load_public_key(i, kv->value); } if (!kv || ret) { fprintf(stderr, "token '%s' has no valid '%s' or '%s' value\n", s[i].section, INI_PUBLIC_KEY, INI_CERT); /* * a bit nasty, but removing the section * in-place means we have to do over the value * of i we just used */ remove_section(i--); continue; } } }