/*- * Copyright (c) 2006 Fredrik Lindberg. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id: birdb.c 57 2006-02-23 14:15:13Z fli $ */ #include #include #include #include #include #include #include #include static int nextline(FILE *, size_t *); static void commentclr(char *); static void rltrim(char *); /* * Initializes a new birdb handle */ birdb * birdb_init(void) { birdb * bdb; bdb = malloc(sizeof(birdb)); if (bdb == NULL) return (NULL); TAILQ_INIT(&bdb->modhead); return (bdb); } /* * Closes a birdb handle * Arguments * bdb - Pointer to a birdb handle */ void birdb_close(birdb *bdb) { struct birdb_mod *bm; while (!TAILQ_EMPTY(&bdb->modhead)) { bm = TAILQ_FIRST(&bdb->modhead); dlclose(bm->bm_dlh); TAILQ_REMOVE(&bdb->modhead, bm, entries); free(bm); } free(bdb); } /* * Load a database backend module into memory * Arguments * bdb - Pointer to a birdb handle * path - Path to module * * Returns a pointer to the new module, NULL on failure */ struct birdb_mod * birdb_addmod(birdb *bdb, const char *path) { struct birdb_mod *bm; bm = malloc(sizeof(struct birdb_mod)); if (bm == NULL) return (NULL); memset(bm, 0, sizeof(struct birdb_mod)); bm->bm_dlh = dlopen(path, RTLD_LAZY); if (bm->bm_dlh == NULL) { warn("%s", dlerror()); goto error; } bm->bm_be = dlsym(bm->bm_dlh, BIRDB_BACKEND_OBJ); if (bm->bm_be == NULL) { warn("%s", dlerror()); goto error; } TAILQ_INSERT_TAIL(&bdb->modhead, bm, entries); return (bm); error: free(bm); return (NULL); } /* * Parse configuration file and load backend modules * Arguments * bdb - Pointer to a birdb handle * path - Path to configuration file * * Ths might load any number of modules. The number of * modules loaded is returned. On failure < 0 is returned. */ int birdb_cfgparse(birdb *bdb, const char *path) { FILE *cfg; size_t len, linesz = 80, rlen; char *buf, *tmp, **argv; int state, argc, retval; struct birdb_mod *bm; char modpath[FILENAME_MAX]; enum { CFGSTATE_BODY, CFGSTATE_SECTION }; state = CFGSTATE_BODY; retval = 0; cfg = fopen(path, "r"); if (cfg == NULL) return (-1); buf = malloc(linesz); if (buf == NULL) return (-1); #define CFG_MODSEC_START " %s = {" #define CFG_MODSEC_END "}" #define CFG_MODSEC_PATH " path = \"%[^\"]\" " #define CFG_MODSEC_ARG " arg = \"%[^\"]\" " while (nextline(cfg, &len) != EOF) { /* Expand our buffer if the line doesn't fit */ if (len > linesz) { buf = realloc(buf, linesz = (len + 4)); } /* Read from file and '\0'-terminate */ rlen = fread(buf, 1, len, cfg); buf[rlen - 1] = '\0'; /* Remove comments and trim whitespaces */ commentclr(buf); rltrim(buf); if (strlen(buf) == 0) continue; tmp = malloc(strlen(buf) + 1); switch (state) { case CFGSTATE_BODY: if (sscanf(buf, CFG_MODSEC_START, tmp) == 1) { state = CFGSTATE_SECTION; argc = 0; argv = NULL; } break; case CFGSTATE_SECTION: if (sscanf(buf, CFG_MODSEC_PATH, tmp) == 1) strncpy(modpath, tmp, FILENAME_MAX - 1); else if (sscanf(buf, CFG_MODSEC_ARG, tmp) == 1) { argv = realloc(argv, sizeof(char *) * ++argc); argv[argc - 1] = malloc(strlen(tmp) + 1); strncpy(argv[argc - 1], tmp, strlen(tmp) + 1); } else if (strcmp(buf, CFG_MODSEC_END) == 0) { if (modpath != NULL) { bm = birdb_addmod(bdb, modpath); if (bm != NULL) { bm->bm_argc = argc; bm->bm_argv = argv; retval++; } } state = CFGSTATE_BODY; } break; } free(tmp); } #undef CFG_MODSEC_START #undef CFG_MODSEC_END #undef CFG_MODSEC_PATH #undef CFG_MODSEC_ARG free(buf); fclose(cfg); return (retval); } /* * Return position and length of next logical line (separated by \n) */ static int nextline(FILE *fp, size_t *len) { int ch; long tmp, newlen = 0; /* Save our file position */ tmp = ftell(fp); /* Seek until we hit \n (end of line) or EOF */ do { #if __POSIX_VISIBLE >= 199506 ch = getc_unlocked(fp); #else ch = getc(fp); #endif newlen++; } while ((ch != EOF) && ((char)ch != '\n')); /* Restore position to previous value */ fseek(fp, tmp, SEEK_SET); *len = newlen; return (ch); } /* * Truncate string at the occurance of a '#'-character */ static void commentclr(char *str) { char *p = str; do { if (*p == '#') { *p = 0; } } while (*p++ != 0); } /* * Remove leading and trailing whitespaces from ``buffer'' */ static void rltrim(char *buffer) { char *p, *q; size_t len = strlen(buffer); for (p = buffer; *p == ' ' || *p == '\t'; p++); for (q = buffer + len - 1; *q == ' ' || *q == '\t'; q--) *q = '\0'; memmove(buffer, p, len - (p - buffer)); buffer[len - (p - buffer)] = '\0'; } /* * Find a database backend module * Arguments * bdb - Pointer to a birdb handle * be_name - backend identifier * * Returns a pointer to the module handle or NULL if no * module could be found. */ struct birdb_mod * birdb_findmod(birdb *bdb, const char *be_name) { struct birdb_mod *bm, *bm_tmp; TAILQ_FOREACH_SAFE(bm, &bdb->modhead, entries, bm_tmp) { if (strcmp(bm->bm_be->be_name, be_name) == 0) break; } return (bm); } /* * Remove a database backend module from memory * Arguments * bdb - Pointer to a birdb handle * bm - Pointer to a module handle */ void birdb_delmod(birdb *bdb, struct birdb_mod *bm) { int i; for (i = 0; i < bm->bm_argc; i++) free(bm->bm_argv[i]); free(bm->bm_argv); dlclose(bm->bm_dlh); TAILQ_REMOVE(&bdb->modhead, bm, entries); free(bm); } /* * Get a list of all backend modules currently loaded * Arguments * bdb - Pointer to a birdb handle * elms - Pointer to a integer, will be set to the * number of modules loaded. * * Returns an array of module handles, this list must be * freed with birdb_backend_freemodlist. */ struct birdb_mod ** birdb_getmodlist(birdb *bdb, int *elms) { struct birdb_mod *bm, *bm_tmp, **bm_res = NULL; size_t sz = 0; int i = 0; TAILQ_FOREACH_SAFE(bm, &bdb->modhead, entries, bm_tmp) { bm_res = realloc(bm_res, (sz += sizeof(struct birdb_mod *))); bm_res[i++] = bm; } *elms = i; return (bm_res); } /* * Free the results returned from getmodlist * Arguments * bm - Array of backend module handles */ void birdb_freemodlist(struct birdb_mod **bm) { if (bm != NULL) free(bm); } /* * Get backend module name */ const char * birdb_backend_getname(struct birdb_mod *bm) { return (const char *)(bm->bm_be->be_name); } /* * Get backend module description */ const char * birdb_backend_getdesc(struct birdb_mod *bm) { return (const char *)(bm->bm_be->be_desc); } /* * Call backend modules open routine * Returns a backend handle. * NULL is treated as a failure; */ void * birdb_backend_open(struct birdb_mod *bm, const char *bspid, int argc, char *argv[]) { return bm->bm_be->be_open(bspid, argc, argv); } /* * Call backend modules close routine * Arguments * bm - Backend module handle * beh - Backend handle */ void birdb_backend_close(struct birdb_mod *bm, void *beh) { return bm->bm_be->be_close(beh); } /* * Call backend modules get routine * Arguments * bm - Backend module handle * beh - Backend handle * rec - BIR database record * * Returns a list of suitable matches */ struct birdb_rec ** birdb_backend_get(struct birdb_mod *bm, void *beh, struct birdb_rec *rec) { return bm->bm_be->be_get(beh, rec); } void birdb_backend_freegetres(struct birdb_mod *bm, void *beh, struct birdb_rec **rec) { return bm->bm_be->be_freegetres(beh, rec); } /* * Call backend modules insert routine * Arguments * bm - Backend module handle * beh - Backend handle * rec - BIR database record to be inserted * * Returns 0 on success, non-zero otherwise. */ int birdb_backend_ins(struct birdb_mod *bm, void *beh, struct birdb_rec *rec) { rec->br_ctime = time(NULL); return bm->bm_be->be_ins(beh, rec); } /* * Call backend modules delete routine * Arguments * bm - Backend module handle * beh - Backend handle * rec - BIR database record to be deleted * * Returns 0 on success, non-zero otherwise. */ int birdb_backend_del(struct birdb_mod *bm, void *beh, struct birdb_rec *rec) { return bm->bm_be->be_del(beh, rec); } /* * Call backend module get first routine * Arguments * bm - Backend module handle * beh - Backend handle * * Returns the first record in database */ struct birdb_rec * birdb_backend_seqgetfirst(struct birdb_mod *bm, void *beh) { return bm->bm_be->be_seqgetfirst(beh); } /* * Call backend module get next routine * Arguments * bm - Backend module handle * beh - Backend handle * rec - Previous record * * Returns the next record in database, NULL on EOF */ struct birdb_rec * birdb_backend_seqgetnext(struct birdb_mod *bm, void *beh, struct birdb_rec *rec) { return bm->bm_be->be_seqgetnext(beh, rec); } /* * Free remaining bits from the get next/get first routines * Arguments * bm - Backend module handle * beh - Backend handle * rec - Previous/last record */ void birdb_backend_seqfree(struct birdb_mod *bm, void *beh, struct birdb_rec *rec) { return bm->bm_be->be_seqfree(beh, rec); } /* * Free a birdb record * Arguments * rec - record to be freed */ void birdb_freerec(struct birdb_rec *rec) { if (rec == NULL); return; if (rec->br_key != NULL) free(rec->br_key); if (rec->br_bir != NULL) { free(rec->br_bir->BiometricData); if (rec->br_bir->Signature) { free(rec->br_bir->Signature->Data); free(rec->br_bir->Signature); } free(rec->br_bir); } free(rec); }