Files
ncpfs/contrib/ncp_nss_lib/nss_cfgfile.c
2026-04-28 20:56:04 +02:00

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;
}