348 lines
7.9 KiB
C
348 lines
7.9 KiB
C
/*
|
|
nss_cfgfile.c - Configuration file handling
|
|
Copyright (C) 2000 Petr Vandrovec
|
|
Copyright (C) 2003 Patrick Pollet
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
Revision history:
|
|
|
|
1.00 2003, Jan 16 Patrick Pollet <patrick.pollet@insa-lyon.fr>
|
|
Initial revision, stronly inspired by ncpfs/lib/cfgfile.c
|
|
|
|
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
|
|
#include "private/libncp-lock.h"
|
|
|
|
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <sys/syslog.h>
|
|
|
|
#include "nss_cfgfile.h"
|
|
#include "nss_ncp.h"
|
|
// temporary define (waiting for a better Makefile)
|
|
#define GLOBALCFGFILE "/etc/ncpfs.conf"
|
|
#ifndef GLOBALCFGFILE
|
|
#error "GLOBALCFGFILE must be defined"
|
|
#endif
|
|
|
|
|
|
// #define DEBUG 1
|
|
|
|
static struct nss_ncp_conf*
|
|
alloc_nss_ncp_conf(void)
|
|
{
|
|
struct nss_ncp_conf * conf;
|
|
|
|
conf = malloc(sizeof(*conf));
|
|
if (!conf)
|
|
return NULL;
|
|
return conf;
|
|
}
|
|
|
|
|
|
void
|
|
free_nss_ncp_conf(struct nss_ncp_conf *conf)
|
|
{
|
|
#define FREEFIELD(x) do if (conf->x) { free(conf->x); conf->x = NULL; } while (0);
|
|
if (conf) {
|
|
FREEFIELD(server);
|
|
FREEFIELD(startCtx);
|
|
FREEFIELD(ctrlGroup);
|
|
FREEFIELD(defShell);
|
|
}
|
|
#undef FREEFIELD
|
|
}
|
|
|
|
|
|
struct cfgFile {
|
|
ncpt_mutex_t mutex;
|
|
FILE* file;
|
|
};
|
|
|
|
static struct cfgFile*
|
|
cfgOpenFile(const char* path,
|
|
int writeRequired)
|
|
{
|
|
struct cfgFile* cfg;
|
|
|
|
cfg = malloc(sizeof(*cfg));
|
|
if (cfg) {
|
|
cfg->file = fopen(path, writeRequired ? "r+" : "r");
|
|
if (cfg->file) {
|
|
ncpt_mutex_init(&cfg->mutex);
|
|
} else {
|
|
free(cfg);
|
|
cfg = NULL;
|
|
}
|
|
}
|
|
return cfg;
|
|
}
|
|
|
|
static void
|
|
cfgClose(struct cfgFile* cfg)
|
|
{
|
|
ncpt_mutex_lock(&cfg->mutex);
|
|
fclose(cfg->file);
|
|
ncpt_mutex_destroy(&cfg->mutex);
|
|
free(cfg);
|
|
}
|
|
|
|
|
|
struct check {
|
|
const char *option; /* configuration option */
|
|
int mandatory; /* can be empty or null */
|
|
int found; /* set to TRUE if found in cfg file */
|
|
char **char_ptr; /* where to store string value */
|
|
int *int_ptr; /* where to store integer value */
|
|
const char *defValue; /* default value */
|
|
};
|
|
|
|
|
|
#ifdef DEBUG
|
|
void
|
|
printResults(const char *infos, const struct check *results)
|
|
{
|
|
const struct check *ptr;
|
|
|
|
printf ("%s\n", infos);
|
|
for (ptr = results; ptr->option; ptr++) {
|
|
if (ptr->int_ptr)
|
|
printf ("option=%s mandatory=%d found=%d value=%d defvalue=%s\n",
|
|
ptr->option, ptr->mandatory, ptr->found, *ptr->int_ptr, ptr->defValue);
|
|
else
|
|
printf ("option=%s mandatory=%d found=%d value=%s defvalue=%s\n",
|
|
ptr->option, ptr->mandatory, ptr->found, *ptr->char_ptr, ptr->defValue);
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
printConf(const char *infos, const struct nss_ncp_conf *conf)
|
|
{
|
|
printf ("%s\n", infos);
|
|
printf ("debug=%d useTree=%d server=%s startCtx=%s ctrlGroup=%s defGid=%u defShell=%s fallbackUid=%u fallbackGid=%u "
|
|
"doPassword=%d doGroup=%d doShadow=%d\n",
|
|
conf->debug, conf->useTree, conf->server, conf->startCtx,
|
|
conf->ctrlGroup, conf->defGid, conf->defShell, conf->fallbackUid, conf->fallbackGid,
|
|
conf->doPassword, conf->doGroup, conf->doShadow);
|
|
}
|
|
#endif
|
|
|
|
|
|
static int
|
|
process_line(const char *cptr, struct check *ptr)
|
|
{
|
|
|
|
const char* sptr; // start of real value
|
|
const char* eptr; // end of real value
|
|
|
|
char ec;
|
|
char cc;
|
|
|
|
while (*cptr && isspace(*cptr))
|
|
cptr++;
|
|
if (*cptr != '=' && *cptr != ':')
|
|
return 1; //no equal sign found
|
|
cptr++;
|
|
|
|
while (*cptr && isspace(*cptr))
|
|
cptr++;
|
|
|
|
// space are allowed in value only if surrounded by " or ' (eg a NDS control group)
|
|
if (*cptr == '"' || *cptr == '\'')
|
|
ec = *cptr++;
|
|
else
|
|
ec = 0;
|
|
sptr = cptr;
|
|
eptr = cptr;
|
|
while ((cc = *cptr++) != 0) {
|
|
if (cc == '\n')
|
|
break;
|
|
if (!ec && isspace(cc))
|
|
break;
|
|
if (cc == ec)
|
|
break;
|
|
eptr++;
|
|
}
|
|
if (eptr != sptr) {
|
|
if (ptr->int_ptr) {
|
|
char* errPtr; // err
|
|
|
|
*ptr->int_ptr = strtoul(sptr, &errPtr, 0);
|
|
ptr->found = errPtr == eptr;
|
|
} else {
|
|
char *v = malloc(eptr - sptr + 1);
|
|
if (v) {
|
|
memcpy(v, sptr, eptr - sptr);
|
|
v[eptr - sptr] = 0;
|
|
*ptr->char_ptr = v;
|
|
ptr->found = TRUE;
|
|
} else
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
fix_conf(struct check *results)
|
|
{
|
|
struct check* ptr;
|
|
|
|
for (ptr = results; ptr->option; ptr++) {
|
|
if (!ptr->found) {
|
|
if (ptr->mandatory) {
|
|
traceForce(0, LOG_ERR, "ncp_nss aborting :missing mandatory information '%s=' in config file %s", ptr->option, GLOBALCFGFILE);
|
|
return 1;
|
|
}
|
|
if (ptr->int_ptr) {
|
|
*ptr->int_ptr = strtoul(ptr->defValue, NULL, 0);
|
|
} else {
|
|
char *v = strdup(ptr->defValue);
|
|
if (v)
|
|
*ptr->char_ptr = v;
|
|
else
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static struct nss_ncp_conf *
|
|
read_conf_file(const char * mySection, struct cfgFile *cfg)
|
|
{
|
|
struct nss_ncp_conf *conf;
|
|
|
|
conf = alloc_nss_ncp_conf();
|
|
if (!conf)
|
|
return NULL;
|
|
{
|
|
struct check check_confs[] = {
|
|
/*option mandati found char_ptr int_ptr defValue */
|
|
{"debug", FALSE, FALSE, NULL, &conf->debug, "0"},
|
|
{"useTree", FALSE, FALSE, NULL, &conf->useTree, "0"},
|
|
{"server", TRUE, FALSE, &conf->server, NULL, ""},
|
|
{"startCtx", FALSE, FALSE, &conf->startCtx, NULL, ""},
|
|
{"ctrlGroup", FALSE, FALSE, &conf->ctrlGroup, NULL, ""},
|
|
{"defGid", FALSE, FALSE, NULL, &conf->defGid, "100"},
|
|
{"defShell", FALSE, FALSE, &conf->defShell, NULL, "/bin/bash"},
|
|
{"fallbackUid", FALSE, FALSE, NULL, &conf->fallbackUid, "-1"},
|
|
{"fallbackGid", FALSE, FALSE, NULL, &conf->fallbackGid, "-1"},
|
|
{"doPasswd", FALSE, FALSE, NULL, &conf->doPassword, "0"},
|
|
{"doGroup", FALSE, FALSE, NULL, &conf->doGroup, "0"},
|
|
{"doShadow", FALSE, FALSE, NULL, &conf->doShadow, "0"},
|
|
{NULL, FALSE, FALSE, NULL, NULL, NULL}
|
|
};
|
|
|
|
char cfgline[16384];
|
|
size_t seclen = strlen(mySection);
|
|
|
|
#ifdef DEBUG
|
|
// DO NOT DO IT A a second call (using test_ncp_nss -2) coredump !!!
|
|
// printResults("before reading CFG", check_confs);
|
|
#endif
|
|
ncpt_mutex_lock(&cfg->mutex);
|
|
//rewind(cfg->file);
|
|
while (fgets(cfgline, sizeof(cfgline)-1, cfg->file)) {
|
|
char* cptr = cfgline;
|
|
struct check* ptr;
|
|
|
|
while (*cptr && isspace(*cptr))
|
|
cptr++;
|
|
if (*cptr != '[')
|
|
continue;
|
|
if (strncasecmp(++cptr, mySection, seclen))
|
|
continue;
|
|
if (cptr[seclen] != ']')
|
|
continue;
|
|
while (fgets(cfgline, sizeof(cfgline) - 1, cfg->file)) {
|
|
cptr = cfgline;
|
|
|
|
while (*cptr && isspace(*cptr))
|
|
cptr++;
|
|
if (!*cptr)
|
|
continue; //empty line
|
|
if (*cptr == '[') // start of another section
|
|
goto ssend;
|
|
for (ptr = check_confs; ptr->option; ptr++) {
|
|
size_t keylen = strlen(ptr->option);
|
|
if (!strncasecmp(cptr, ptr->option, keylen)) {
|
|
cptr += keylen;
|
|
process_line(cptr, ptr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ssend:
|
|
#ifdef DEBUG
|
|
printResults("after reading CFG no error", check_confs);
|
|
#endif
|
|
#ifdef DEBUG
|
|
printConf("before fixing ", conf);
|
|
#endif
|
|
|
|
if (!fix_conf (check_confs)) { // fill in missing values with default,
|
|
#ifdef DEBUG
|
|
printConf("after fixing ", conf);
|
|
#endif
|
|
ncpt_mutex_unlock(&cfg->mutex);
|
|
return conf;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printResults("after reading CFG error", check_confs);
|
|
#endif
|
|
ncpt_mutex_unlock(&cfg->mutex);
|
|
free_nss_ncp_conf(conf);
|
|
return NULL;
|
|
}
|
|
|
|
}
|
|
|
|
struct nss_ncp_conf*
|
|
parse_conf(void)
|
|
{
|
|
struct cfgFile *cfg;
|
|
struct nss_ncp_conf *conf;
|
|
#ifdef DEBUG
|
|
printf("entering parse_conf\n");
|
|
#endif
|
|
cfg = cfgOpenFile(GLOBALCFGFILE, FALSE);
|
|
if (!cfg)
|
|
return NULL;
|
|
conf = read_conf_file(NSS_SECTION, cfg);
|
|
cfgClose(cfg);
|
|
#ifdef DEBUG
|
|
if (conf)
|
|
printConf("final value ", conf);
|
|
#endif
|
|
|
|
return conf;
|
|
}
|
|
|