Mercurial > dovecot > core-2.2
view src/lib-settings/settings.c @ 3879:928229f8b3e6 HEAD
deinit, unref, destroy, close, free, etc. functions now take a pointer to
their data pointer, and set it to NULL. This makes double-frees less likely
to cause security holes.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 14 Jan 2006 20:47:20 +0200 |
parents | 55df57c028d4 |
children | 71b8faa84ec6 |
line wrap: on
line source
/* Copyright (C) 2002 Timo Sirainen */ #include "lib.h" #include "istream.h" #include "strescape.h" #include "settings.h" #include <stdio.h> #include <fcntl.h> static const char *get_bool(const char *value, bool *result) { if (strcasecmp(value, "yes") == 0) *result = TRUE; else if (strcasecmp(value, "no") == 0) *result = FALSE; else return t_strconcat("Invalid boolean: ", value, NULL); return NULL; } static const char *get_uint(const char *value, unsigned int *result) { int num; if (!sscanf(value, "%i", &num) || num < 0) return t_strconcat("Invalid number: ", value, NULL); *result = num; return NULL; } const char * parse_setting_from_defs(pool_t pool, struct setting_def *defs, void *base, const char *key, const char *value) { struct setting_def *def; for (def = defs; def->name != NULL; def++) { if (strcmp(def->name, key) == 0) { void *ptr = STRUCT_MEMBER_P(base, def->offset); switch (def->type) { case SET_STR: *((char **) ptr) = p_strdup_empty(pool, value); return NULL; case SET_INT: /* use %i so we can handle eg. 0600 as octal value with umasks */ return get_uint(value, (unsigned int *) ptr); case SET_BOOL: return get_bool(value, (bool *) ptr); } } } return t_strconcat("Unknown setting: ", key, NULL); } #define IS_WHITE(c) ((c) == ' ' || (c) == '\t') bool settings_read(const char *path, const char *section, settings_callback_t *callback, settings_section_callback_t *sect_callback, void *context) { struct istream *input; const char *errormsg, *next_section; char *line, *key, *name, *p, quote; size_t len; int fd, linenum, skip, sections, root_section; fd = open(path, O_RDONLY); if (fd < 0) { i_error("Can't open configuration file %s: %m", path); return FALSE; } t_push(); if (section == NULL) { skip = 0; next_section = NULL; } else { skip = 1; next_section = t_strcut(section, '/'); } linenum = 0; sections = 0; root_section = 0; errormsg = NULL; input = i_stream_create_file(fd, default_pool, 2048, TRUE); while ((line = i_stream_read_next_line(input)) != NULL) { linenum++; /* @UNSAFE: line is modified */ /* skip whitespace */ while (IS_WHITE(*line)) line++; /* ignore comments or empty lines */ if (*line == '#' || *line == '\0') continue; /* strip away comments. pretty kludgy way really.. */ for (p = line; *p != '\0'; p++) { if (*p == '\'' || *p == '"') { quote = *p; for (p++; *p != quote && *p != '\0'; p++) { if (*p == '\\' && p[1] != '\0') p++; } if (*p == '\0') break; } else if (*p == '#') { *p = '\0'; break; } } /* remove whitespace from end of line */ len = strlen(line); while (IS_WHITE(line[len-1])) len--; line[len] = '\0'; /* a) key = value b) section_type [section_name] { c) } */ key = line; while (!IS_WHITE(*line) && *line != '\0' && *line != '=') line++; if (IS_WHITE(*line)) { *line++ = '\0'; while (IS_WHITE(*line)) line++; } if (*line == '=') { /* a) */ *line++ = '\0'; while (IS_WHITE(*line)) line++; len = strlen(line); if (len > 0 && ((*line == '"' && line[len-1] == '"') || (*line == '\'' && line[len-1] == '\''))) { line[len-1] = '\0'; line = str_unescape(line+1); } errormsg = skip ? NULL : callback(key, line, context); } else if (strcmp(key, "}") != 0 || *line != '\0') { /* b) + errors */ line[-1] = '\0'; if (*line == '{') name = ""; else { name = line; while (!IS_WHITE(*line) && *line != '\0') line++; if (*line != '\0') { *line++ = '\0'; while (IS_WHITE(*line)) line++; } } if (*line != '{') errormsg = "Expecting '='"; else { sections++; if (next_section != NULL && strcmp(next_section, name) == 0) { section += strlen(next_section); if (*section == '\0') { skip = 0; next_section = NULL; root_section = sections; } else { i_assert(*section == '/'); section++; next_section = t_strcut(section, '/'); } } if (skip > 0) skip++; else { skip = sect_callback == NULL ? 1 : !sect_callback(key, name, context, &errormsg); } } } else { /* c) */ if (sections == 0) errormsg = "Unexpected '}'"; else { if (skip > 0) skip--; else { sect_callback(NULL, NULL, context, &errormsg); if (root_section == sections && errormsg == NULL) { /* we found the section, now quit */ break; } } sections--; } } if (errormsg != NULL) { i_error("Error in configuration file %s line %d: %s", path, linenum, errormsg); break; } } i_stream_unref(&input); t_pop(); return errormsg == NULL; }