sss_colondb.c revision a76f63544533f0404f7711a10c1a621c6045df17
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek/*
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek Authors:
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek Pavel Březina <pbrezina@redhat.com>
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek Copyright (C) 2015 Red Hat
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek This program is free software; you can redistribute it and/or modify
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek it under the terms of the GNU General Public License as published by
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek the Free Software Foundation; either version 3 of the License, or
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek (at your option) any later version.
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek This program is distributed in the hope that it will be useful,
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek but WITHOUT ANY WARRANTY; without even the implied warranty of
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek GNU General Public License for more details.
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek You should have received a copy of the GNU General Public License
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek along with this program. If not, see <http://www.gnu.org/licenses/>.
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek*/
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek#include <stdlib.h>
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek#include "util/util.h"
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek#include "util/strtonum.h"
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek#include "tools/common/sss_colondb.h"
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek#define IS_STD_FILE(db) ((db)->file == stdin || (db)->file == stdout)
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozekstatic char *read_field_as_string(char *line,
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek const char **_value)
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek{
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek char *rest;
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek char *value;
5cd4414fce1e0eb4133dfc6fc828bf25c8a959f9Lukas Slebodnik
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek if (line == NULL || *line == '\n' || *line == '\0') {
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek /* There is nothing else to read. */
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek rest = NULL;
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek value = NULL;
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek goto done;
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek }
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek if (*line == ':') {
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek /* Special case for empty value. */
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek *line = '\0';
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek rest = line + 1;
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek value = NULL;
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek goto done;
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek }
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* Value starts at current position. */
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek value = line;
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek /* Find next field delimiter. */
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek rest = strchr(line, ':');
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek if (rest == NULL) {
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek /* There is no more field. Remove \n from the end. */
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek rest = strchr(line, '\n');
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek if (rest != NULL) {
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek *rest = '\0';
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek rest = NULL;
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek }
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek goto done;
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek }
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek /* Remove it and step one character further. */
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek *rest = '\0';
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov rest++;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozekdone:
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek *_value = value;
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek return rest;
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek}
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozekstatic char *read_field_as_uint32(char *line,
uint32_t *_value)
{
const char *str;
char *rest;
errno_t ret;
rest = read_field_as_string(line, &str);
if (str == NULL) {
*_value = 0;
return rest;
}
*_value = strtouint32(str, NULL, 10);
if (errno != 0) {
ret = errno;
DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse number [%d]: %s\n",
ret, sss_strerror(ret));
*_value = 0;
}
return rest;
}
struct sss_colondb {
FILE *file;
enum sss_colondb_mode mode;
};
errno_t sss_colondb_readline(TALLOC_CTX *mem_ctx,
struct sss_colondb *db,
struct sss_colondb_read_field *table)
{
int readchars;
size_t linelen = 0;
char *line = NULL;
char *tcline;
char *rest;
errno_t ret;
int i;
if (db->mode != SSS_COLONDB_READ) {
return ERR_INTERNAL;
}
readchars = getline(&line, &linelen, db->file);
if (readchars == -1) {
/* Nothing was read. */
if (errno != 0) {
ret = errno;
DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read line [%d]: %s",
ret, sss_strerror(ret));
return ret;
}
return EOF;
}
/* Copy line to mem_ctx. */
tcline = talloc_strdup(mem_ctx, line);
free(line);
line = NULL;
if (tcline == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
return ENOMEM;
}
rest = tcline;
for (i = 0; table[i].type != SSS_COLONDB_SENTINEL; i++) {
switch (table[i].type) {
case SSS_COLONDB_UINT32:
rest = read_field_as_uint32(rest, table[i].data.uint32);
break;
case SSS_COLONDB_STRING:
rest = read_field_as_string(rest, table[i].data.str);
break;
case SSS_COLONDB_SENTINEL:
DEBUG(SSSDBG_CRIT_FAILURE, "Trying to process sentinel?!\n");
ret = ERR_INTERNAL;
goto done;
}
if (rest == NULL && table[i + 1].type != SSS_COLONDB_SENTINEL) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Line contains less values than expected!\n");
ret = EINVAL;
goto done;
} else if (rest != NULL && table[i + 1].type == SSS_COLONDB_SENTINEL) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Line contains more values than expected!\n");
ret = EINVAL;
goto done;
}
}
ret = EOK;
done:
if (ret != EOK) {
talloc_free(tcline);
}
return ret;
}
errno_t sss_colondb_writeline(struct sss_colondb *db,
struct sss_colondb_write_field *table)
{
TALLOC_CTX *tmp_ctx;
char *line = NULL;
errno_t ret;
int i;
if (db->mode != SSS_COLONDB_WRITE) {
return ERR_INTERNAL;
}
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
return ENOMEM;
}
for (i = 0; table[i].type != SSS_COLONDB_SENTINEL; i++) {
switch (table[i].type) {
case SSS_COLONDB_UINT32:
if (table[i].data.uint32 == 0) {
line = talloc_asprintf_append(line, ":");
} else {
line = talloc_asprintf_append(line, ":%u", table[i].data.uint32);
}
break;
case SSS_COLONDB_STRING:
if (table[i].data.str == NULL) {
line = talloc_asprintf_append(line, ":");
} else {
line = talloc_asprintf_append(line, ":%s", table[i].data.str);
}
break;
case SSS_COLONDB_SENTINEL:
DEBUG(SSSDBG_CRIT_FAILURE, "Trying to process sentinel?!\n");
ret = ERR_INTERNAL;
goto done;
}
if (line == NULL) {
ret = ENOMEM;
goto done;
}
}
/* Remove starting : */
line++;
fprintf(db->file, "%s\n", line);
fflush(db->file);
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
static int sss_colondb_close(void *pvt)
{
struct sss_colondb *db = talloc_get_type(pvt, struct sss_colondb);
if (db->file == NULL || IS_STD_FILE(db)) {
return 0;
}
fclose(db->file);
db->file = NULL;
return 0;
}
static FILE *open_db(const char *filename, enum sss_colondb_mode mode)
{
FILE *fp = NULL;
errno_t ret;
errno = 0;
switch (mode) {
case SSS_COLONDB_READ:
fp = filename == NULL ? stdin : fopen(filename, "r");
break;
case SSS_COLONDB_WRITE:
fp = filename == NULL ? stdout : fopen(filename, "w");
break;
}
if (fp == NULL && filename != NULL) {
ret = errno;
DEBUG(SSSDBG_CRIT_FAILURE, "Unable to open file %s [%d]: %s\n",
filename, ret, sss_strerror(ret));
}
return fp;
}
struct sss_colondb *sss_colondb_open(TALLOC_CTX *mem_ctx,
enum sss_colondb_mode mode,
const char *filename)
{
struct sss_colondb *db;
db = talloc_zero(mem_ctx, struct sss_colondb);
if (db == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed\n");
return NULL;
}
db->file = open_db(filename, mode);
db->mode = mode;
if (db->file == NULL) {
talloc_free(db);
return NULL;
}
talloc_set_destructor((TALLOC_CTX *)db, sss_colondb_close);
return db;
}