openldap/contrib/slapd-modules/dsaschema/dsaschema.c
Kurt Zeilenga a5abeb92ec Update contrib notices to reflect that they are distributed as part of
OpenLDAP Software (though they may not necessarily be supported by the
OpenLDAP Project).  Assistance in updating ACKNOWLEDGEMENTS welcomed.
2009-08-16 22:55:23 +00:00

439 lines
8.8 KiB
C

/* dsaschema.c */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2004-2009 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include <portable.h>
#include <ac/string.h>
#include <ac/ctype.h>
#include <ac/signal.h>
#include <ac/errno.h>
#include <ac/stdlib.h>
#include <ac/ctype.h>
#include <ac/time.h>
#include <ac/unistd.h>
#include <stdio.h>
/*
* Schema reader that allows us to define DSA schema (including
* operational attributes and non-user object classes)
*
* A kludge, at best, and in order to avoid including slapd
* headers we use fprintf() rather than slapd's native logging,
* which may confuse users...
*
*/
#include <ldap.h>
#include <ldap_schema.h>
extern int at_add(LDAPAttributeType *at, const char **err);
extern int oc_add(LDAPObjectClass *oc, int user, const char **err);
extern int cr_add(LDAPContentRule *cr, int user, const char **err);
#define ARGS_STEP 512
static char *fp_getline(FILE *fp, int *lineno);
static void fp_getline_init(int *lineno);
static int fp_parse_line(int lineno, char *line);
static char *strtok_quote( char *line, char *sep );
static char **cargv = NULL;
static int cargv_size = 0;
static int cargc = 0;
static char *strtok_quote_ptr;
int init_module(int argc, char *argv[]);
static int dsaschema_parse_at(const char *fname, int lineno, char *line, char **argv)
{
LDAPAttributeType *at;
int code;
const char *err;
at = ldap_str2attributetype(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL);
if (!at) {
fprintf(stderr, "%s: line %d: %s before %s\n",
fname, lineno, ldap_scherr2str(code), err);
return 1;
}
if (at->at_oid == NULL) {
fprintf(stderr, "%s: line %d: attributeType has no OID\n",
fname, lineno);
return 1;
}
code = at_add(at, &err);
if (code) {
fprintf(stderr, "%s: line %d: %s: \"%s\"\n",
fname, lineno, ldap_scherr2str(code), err);
return 1;
}
ldap_memfree(at);
return 0;
}
static int dsaschema_parse_oc(const char *fname, int lineno, char *line, char **argv)
{
LDAPObjectClass *oc;
int code;
const char *err;
oc = ldap_str2objectclass(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL);
if (!oc) {
fprintf(stderr, "%s: line %d: %s before %s\n",
fname, lineno, ldap_scherr2str(code), err);
return 1;
}
if (oc->oc_oid == NULL) {
fprintf(stderr,
"%s: line %d: objectclass has no OID\n",
fname, lineno);
return 1;
}
code = oc_add(oc, 0, &err);
if (code) {
fprintf(stderr, "%s: line %d: %s: \"%s\"\n",
fname, lineno, ldap_scherr2str(code), err);
return 1;
}
ldap_memfree(oc);
return 0;
}
static int dsaschema_parse_cr(const char *fname, int lineno, char *line, char **argv)
{
LDAPContentRule *cr;
int code;
const char *err;
cr = ldap_str2contentrule(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL);
if (!cr) {
fprintf(stderr, "%s: line %d: %s before %s\n",
fname, lineno, ldap_scherr2str(code), err);
return 1;
}
if (cr->cr_oid == NULL) {
fprintf(stderr,
"%s: line %d: objectclass has no OID\n",
fname, lineno);
return 1;
}
code = cr_add(cr, 0, &err);
if (code) {
fprintf(stderr, "%s: line %d: %s: \"%s\"\n",
fname, lineno, ldap_scherr2str(code), err);
return 1;
}
ldap_memfree(cr);
return 0;
}
static int dsaschema_read_config(const char *fname, int depth)
{
FILE *fp;
char *line, *savefname, *saveline;
int savelineno, lineno;
int rc;
if (depth == 0) {
cargv = calloc(ARGS_STEP + 1, sizeof(*cargv));
if (cargv == NULL) {
return 1;
}
cargv_size = ARGS_STEP + 1;
}
fp = fopen(fname, "r");
if (fp == NULL) {
fprintf(stderr, "could not open config file \"%s\": %s (%d)\n",
fname, strerror(errno), errno);
return 1;
}
fp_getline_init(&lineno);
while ((line = fp_getline(fp, &lineno)) != NULL) {
/* skip comments and blank lines */
if (line[0] == '#' || line[0] == '\0') {
continue;
}
saveline = strdup(line);
if (saveline == NULL) {
return 1;
}
if (fp_parse_line(lineno, line) != 0) {
return 1;
}
if (cargc < 1) {
continue;
}
if (strcasecmp(cargv[0], "attributetype") == 0 ||
strcasecmp(cargv[0], "attribute") == 0) {
if (cargc < 2) {
fprintf(stderr, "%s: line %d: illegal attribute type format\n",
fname, lineno);
return 1;
} else if (*cargv[1] == '(' /*')'*/) {
char *p;
p = strchr(saveline, '(' /*')'*/);
rc = dsaschema_parse_at(fname, lineno, p, cargv);
if (rc != 0)
return rc;
} else {
fprintf(stderr, "%s: line %d: old attribute type format not supported\n",
fname, lineno);
}
} else if (strcasecmp(cargv[0], "ditcontentrule") == 0) {
char *p;
p = strchr(saveline, '(' /*')'*/);
rc = dsaschema_parse_cr(fname, lineno, p, cargv);
if (rc != 0)
return rc;
} else if (strcasecmp(cargv[0], "objectclass") == 0) {
if (cargc < 2) {
fprintf(stderr, "%s: line %d: illegal objectclass format\n",
fname, lineno);
return 1;
} else if (*cargv[1] == '(' /*')'*/) {
char *p;
p = strchr(saveline, '(' /*')'*/);
rc = dsaschema_parse_oc(fname, lineno, p, cargv);
if (rc != 0)
return rc;
} else {
fprintf(stderr, "%s: line %d: object class format not supported\n",
fname, lineno);
}
} else if (strcasecmp(cargv[0], "include") == 0) {
if (cargc < 2) {
fprintf(stderr, "%s: line %d: missing file name in \"include <filename>\" line",
fname, lineno);
return 1;
}
savefname = strdup(cargv[1]);
if (savefname == NULL) {
return 1;
}
if (dsaschema_read_config(savefname, depth + 1) != 0) {
return 1;
}
free(savefname);
lineno = savelineno - 1;
} else {
fprintf(stderr, "%s: line %d: unknown directive \"%s\" (ignored)\n",
fname, lineno, cargv[0]);
}
}
fclose(fp);
if (depth == 0)
free(cargv);
return 0;
}
int init_module(int argc, char *argv[])
{
int i;
int rc;
for (i = 0; i < argc; i++) {
rc = dsaschema_read_config(argv[i], 0);
if (rc != 0) {
break;
}
}
return rc;
}
static int
fp_parse_line(
int lineno,
char *line
)
{
char * token;
cargc = 0;
token = strtok_quote( line, " \t" );
if ( strtok_quote_ptr ) {
*strtok_quote_ptr = ' ';
}
if ( strtok_quote_ptr ) {
*strtok_quote_ptr = '\0';
}
for ( ; token != NULL; token = strtok_quote( NULL, " \t" ) ) {
if ( cargc == cargv_size - 1 ) {
char **tmp;
tmp = realloc( cargv, (cargv_size + ARGS_STEP) *
sizeof(*cargv) );
if ( tmp == NULL ) {
return -1;
}
cargv = tmp;
cargv_size += ARGS_STEP;
}
cargv[cargc++] = token;
}
cargv[cargc] = NULL;
return 0;
}
static char *
strtok_quote( char *line, char *sep )
{
int inquote;
char *tmp;
static char *next;
strtok_quote_ptr = NULL;
if ( line != NULL ) {
next = line;
}
while ( *next && strchr( sep, *next ) ) {
next++;
}
if ( *next == '\0' ) {
next = NULL;
return( NULL );
}
tmp = next;
for ( inquote = 0; *next; ) {
switch ( *next ) {
case '"':
if ( inquote ) {
inquote = 0;
} else {
inquote = 1;
}
AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
break;
case '\\':
if ( next[1] )
AC_MEMCPY( next,
next + 1, strlen( next + 1 ) + 1 );
next++; /* dont parse the escaped character */
break;
default:
if ( ! inquote ) {
if ( strchr( sep, *next ) != NULL ) {
strtok_quote_ptr = next;
*next++ = '\0';
return( tmp );
}
}
next++;
break;
}
}
return( tmp );
}
static char buf[BUFSIZ];
static char *line;
static size_t lmax, lcur;
#define CATLINE( buf ) \
do { \
size_t len = strlen( buf ); \
while ( lcur + len + 1 > lmax ) { \
lmax += BUFSIZ; \
line = (char *) realloc( line, lmax ); \
} \
strcpy( line + lcur, buf ); \
lcur += len; \
} while( 0 )
static char *
fp_getline( FILE *fp, int *lineno )
{
char *p;
lcur = 0;
CATLINE( buf );
(*lineno)++;
/* hack attack - keeps us from having to keep a stack of bufs... */
if ( strncasecmp( line, "include", 7 ) == 0 ) {
buf[0] = '\0';
return( line );
}
while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
/* trim off \r\n or \n */
if ( (p = strchr( buf, '\n' )) != NULL ) {
if( p > buf && p[-1] == '\r' ) --p;
*p = '\0';
}
/* trim off trailing \ and append the next line */
if ( line[ 0 ] != '\0'
&& (p = line + strlen( line ) - 1)[ 0 ] == '\\'
&& p[ -1 ] != '\\' ) {
p[ 0 ] = '\0';
lcur--;
} else {
if ( ! isspace( (unsigned char) buf[0] ) ) {
return( line );
}
/* change leading whitespace to a space */
buf[0] = ' ';
}
CATLINE( buf );
(*lineno)++;
}
buf[0] = '\0';
return( line[0] ? line : NULL );
}
static void
fp_getline_init( int *lineno )
{
*lineno = -1;
buf[0] = '\0';
}