Skip to content
Snippets Groups Projects
Commit b2b3581b authored by Julio Sánchez Fernández's avatar Julio Sánchez Fernández
Browse files

Initial incomplete and broken version.
parent 59865a5d
No related branches found
No related tags found
No related merge requests found
/*
* Copyright 1999 The OpenLDAP Foundation, Redwood City, California, USA
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted only
* as authorized by the OpenLDAP Public License. A copy of this
* license is available at http://www.OpenLDAP.org/license.html or
* in file LICENSE in the top-level directory of the distribution.
*/
/*
* ldap-schema.h - Header for basic schema handling functions that can be
* used by both clients and servers.
*/
#ifndef _LDAP_SCHEMA_H
#define _LDAP_SCHEMA_H 1
#include <ldap_cdefs.h>
LDAP_BEGIN_DECL
/* Codes for parsing errors */
#define SCHEMA_ERR_OUTOFMEM 1
#define SCHEMA_ERR_UNEXPTOKEN 2
#define SCHEMA_ERR_NOLEFTPAREN 3
#define SCHEMA_ERR_NORIGHTPAREN 4
#define SCHEMA_ERR_NODIGIT 5
#define SCHEMA_ERR_BADNAME 6
#define SCHEMA_ERR_BADDESC 7
#define SCHEMA_ERR_BADSUP 8
#define SCHEMA_ERR_DUPOPT 9
typedef struct ldap_attributetype {
char *at_oid; /* REQUIRED */
char **at_names; /* OPTIONAL */
char *at_desc; /* OPTIONAL */
int at_obsolete; /* 0=no, 1=yes */
char *at_sup_oid; /* OPTIONAL */
char *at_equality_oid; /* OPTIONAL */
char *at_ordering_oid; /* OPTIONAL */
char *at_substr_oid; /* OPTIONAL */
char *at_syntax_oid; /* OPTIONAL */
int at_syntax_len; /* OPTIONAL */
int at_single_value; /* 0=no, 1=yes */
int at_collective; /* 0=no, 1=yes */
int at_no_user_mod; /* 0=no, 1=yes */
int at_usage; /* 0=userApplications, 1=directoryOperation,
2=distributedOperation, 3=dSAOperation */
} LDAP_ATTRIBUTE_TYPE;
typedef struct ldap_objectclass {
char *oc_oid; /* REQUIRED */
char **oc_names; /* OPTIONAL */
char *oc_desc; /* OPTIONAL */
int oc_obsolete; /* 0=no, 1=yes */
char **oc_sup_oids; /* OPTIONAL */
int oc_kind; /* 0=ABSTRACT, 1=STRUCTURAL, 2=AUXILIARY */
char **oc_at_oids_must; /* OPTIONAL */
char **oc_at_oids_may; /* MAY */
} LDAP_OBJECT_CLASS;
LDAP_F(LDAP_OBJECT_CLASS *) ldap_str2objectclass LDAP_P(( char * s, int * code, char ** errp ));
LDAP_F(LDAP_ATTRIBUTE_TYPE) ldap_str2attributetype LDAP_P(( char * sval, char ** errp ));
LDAP_F( char *) ldap_objectclass2str LDAP_P(( LDAP_OBJECT_CLASS * oc ));
LDAP_F( char *) ldap_attributetype2str LDAP_P(( LDAP_ATTRIBUTE_TYPE * at ));
LDAP_END_DECL
#endif
/*
* Copyright 1999 The OpenLDAP Foundation, All Rights Reserved.
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
*
* schema.c: parsing routines used by servers and clients to process
* schema definitions
*/
#include "portable.h"
#include <ac/ctype.h>
#include <ac/string.h>
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#include <lber.h>
#include <ldap.h>
#include <ldap_schema.h>
#include <stdio.h>
/*
* When pretty printing the entities we will be appending to a buffer.
* Since checking for overflow, realloc'ing and checking if no error
* is extremely boring, we will use a pretection layer that will let
* us blissfully ignore the error until the end. This layer is
* implemented with the help of the next type.
*/
typedef struct safe_string {
char * val;
int size;
int pos;
int at_whsp;
} safe_string;
static safe_string *
new_safe_string(int size)
{
safe_string * ss;
ss = malloc(sizeof(safe_string));
if ( !ss )
return(NULL);
ss->size = size;
ss->pos = 0;
ss->val = malloc(size);
ss->at_whsp = 0;
if ( !ss->val ) {
free(ss);
return(NULL);
}
return ss;
}
void
safe_string_free(safe_string * ss)
{
if ( !ss )
return;
ldap_memfree(ss->val);
ldap_memfree(ss);
}
static char *
safe_string_val(safe_string * ss)
{
return(ss->val);
}
static int
append_to_safe_string(safe_string * ss, char * s)
{
int l = strlen(s);
char * temp;
/*
* Some runaway process is trying to append to a string that
* overflowed and we could not extend.
*/
if ( !ss->val )
return -1;
/* We always make sure there is at least one position available */
if ( ss->pos + l >= ss->size-1 ) {
ss->size *= 2;
temp = realloc(ss->val, ss->size);
if ( !temp ) {
/* Trouble, out of memory */
free(ss->val);
return -1;
}
ss->val = temp;
}
strncpy(&ss->val[ss->pos], s, l);
ss->pos += l;
if ( ss->pos > 0 && ss->val[ss->pos-1] == ' ' )
ss->at_whsp = 1;
else
ss->at_whsp = 0;
return 0;
}
static int
print_literal(safe_string *ss, char *s)
{
return(append_to_safe_string(ss,s));
}
static int
print_whsp(safe_string *ss)
{
if ( ss->at_whsp )
return(append_to_safe_string(ss,""));
else
return(append_to_safe_string(ss," "));
}
static int
print_numericoid(safe_string *ss, char *s)
{
return(append_to_safe_string(ss,s));
}
/* This one is identical to print_qdescr */
static int
print_qdstring(safe_string *ss, char *s)
{
print_whsp(ss);
print_literal(ss,"'");
append_to_safe_string(ss,s);
print_literal(ss,"'");
return(print_whsp(ss));
}
static int
print_qdescr(safe_string *ss, char *s)
{
print_whsp(ss);
print_literal(ss,"'");
append_to_safe_string(ss,s);
print_literal(ss,"'");
return(print_whsp(ss));
}
static int
print_qdescrlist(safe_string *ss, char **sa)
{
char **sp;
int ret = 0;
for (sp=sa; *sp; sp++) {
ret = print_qdescr(ss,*sp);
}
/* If the list was empty, we return zero that is potentially
* incorrect, but since we will still appending things, the
* overflow will be detected later. Maybe FIX.
*/
return(ret);
}
static int
print_qdescrs(safe_string *ss, char **sa)
{
/* The only way to represent an empty list is as a qdescrlist
* so, if the list is empty we treat it as a long list.
* Really, this is what the syntax mandates.
*/
if ( !sa[0] || ( sa[0] && sa[1] ) ) {
print_whsp(ss);
print_literal(ss,"(");
print_qdescrlist(ss,sa);
print_literal(ss,")");
return(print_whsp(ss));
} else {
return(print_qdescr(ss,*sa));
}
}
static int
print_woid(safe_string *ss, char *s)
{
print_whsp(ss);
append_to_safe_string(ss,s);
return print_whsp(ss);
}
static int
print_oidlist(safe_string *ss, char **sa)
{
char **sp;
for (sp=sa; *(sp+1); sp++) {
print_woid(ss,*sp);
print_literal(ss,"$");
}
return(print_woid(ss,*sp));
}
static int
print_oids(safe_string *ss, char **sa)
{
if ( sa[0] && sa[1] ) {
print_literal(ss,"(");
print_oidlist(ss,sa);
print_whsp(ss);
return(print_literal(ss,")"));
} else {
return(print_woid(ss,*sa));
}
}
static int
print_noidlen(safe_string *ss, char *s, int l)
{
char buf[64];
int ret;
ret = print_numericoid(ss,s);
if ( l ) {
sprintf(buf,"{%d}",l);
ret = print_literal(ss,buf);
}
return(ret);
}
char *
ldap_objectclass2str( LDAP_OBJECT_CLASS * oc )
{
safe_string * ss;
char * retstring;
ss = new_safe_string(256);
if ( !ss )
return NULL;
print_literal(ss,"(");
print_whsp(ss);
print_numericoid(ss, oc->oc_oid);
print_whsp(ss);
if ( oc->oc_names ) {
print_literal(ss,"NAME");
print_qdescrs(ss,oc->oc_names);
}
if ( oc->oc_desc ) {
print_literal(ss,"DESC");
print_qdstring(ss,oc->oc_desc);
}
if ( oc->oc_obsolete ) {
print_literal(ss, "OBSOLETE");
print_whsp(ss);
}
if ( oc->oc_sup_oids ) {
print_literal(ss,"SUP");
print_oids(ss,oc->oc_sup_oids);
}
switch (oc->oc_kind) {
case 0:
print_literal(ss,"ABSTRACT");
break;
case 1:
print_literal(ss,"STRUCTURAL");
break;
case 2:
print_literal(ss,"AUXILIARY");
break;
default:
print_literal(ss,"KIND-UNKNOWN");
break;
}
print_whsp(ss);
if ( oc->oc_at_oids_must ) {
print_literal(ss,"MUST");
print_whsp(ss);
print_oids(ss,oc->oc_at_oids_must);
print_whsp(ss);
}
if ( oc->oc_at_oids_may ) {
print_literal(ss,"MAY");
print_whsp(ss);
print_oids(ss,oc->oc_at_oids_may);
print_whsp(ss);
}
print_whsp(ss);
print_literal(ss,")");
retstring = safe_string_val(ss);
safe_string_free(ss);
return(retstring);
}
char *
ldap_attributetype2str( LDAP_ATTRIBUTE_TYPE * at )
{
safe_string * ss;
char * retstring;
ss = new_safe_string(256);
if ( !ss )
return NULL;
print_literal(ss,"(");
print_whsp(ss);
print_numericoid(ss, at->at_oid);
print_whsp(ss);
if ( at->at_names ) {
print_literal(ss,"NAME");
print_qdescrs(ss,at->at_names);
}
if ( at->at_desc ) {
print_literal(ss,"DESC");
print_qdstring(ss,at->at_desc);
}
if ( at->at_obsolete ) {
print_literal(ss, "OBSOLETE");
print_whsp(ss);
}
if ( at->at_sup_oid ) {
print_literal(ss,"SUP");
print_woid(ss,at->at_sup_oid);
}
if ( at->at_equality_oid ) {
print_literal(ss,"EQUALITY");
print_woid(ss,at->at_equality_oid);
}
if ( at->at_ordering_oid ) {
print_literal(ss,"ORDERING");
print_woid(ss,at->at_ordering_oid);
}
if ( at->at_substr_oid ) {
print_literal(ss,"SUBSTR");
print_woid(ss,at->at_substr_oid);
}
if ( at->at_syntax_oid ) {
print_literal(ss,"SYNTAX");
print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
}
if ( at->at_single_value ) {
print_literal(ss,"SINGLE-VALUE");
print_whsp(ss);
}
if ( at->at_collective ) {
print_literal(ss,"COLLECTIVE");
print_whsp(ss);
}
if ( at->at_no_user_mod ) {
print_literal(ss,"NO-USER-MODIFICATION");
print_whsp(ss);
}
if ( at->at_usage ) {
print_literal(ss,"USAGE");
print_whsp(ss);
switch (at->at_usage) {
case 1:
print_literal(ss,"directoryOperation");
break;
case 2:
print_literal(ss,"distributedOperation");
break;
case 3:
print_literal(ss,"dSAOperation");
break;
default:
print_literal(ss,"UNKNOWN");
break;
}
}
print_whsp(ss);
print_literal(ss,")");
retstring = safe_string_val(ss);
safe_string_free(ss);
return(retstring);
}
/*
* This is ripped from servers/slapd/charray.c that should be promoted
* to -lldap or something so that it is used everywhere.
*/
static void
charray_free( char **array )
{
char **a;
if ( array == NULL ) {
return;
}
for ( a = array; *a != NULL; a++ ) {
if ( *a != NULL ) {
free( *a );
}
}
free( (char *) array );
}
#define TK_NOENDQUOTE -2
#define TK_OUTOFMEM -1
#define TK_EOS 0
#define TK_UNEXPCHAR 1
#define TK_BAREWORD 2
#define TK_QDSTRING 3
#define TK_LEFTPAREN 4
#define TK_RIGHTPAREN 5
#define TK_DOLLAR 6
#define TK_QDESCR TK_QDSTRING
struct token {
int type;
char *sval;
};
static int
get_token(char ** sp, char ** token_val)
{
int kind;
char * p;
char * q;
char * res;
switch (**sp) {
case '\0':
kind = TK_EOS;
(*sp)++;
break;
case '(':
kind = TK_LEFTPAREN;
(*sp)++;
break;
case ')':
kind = TK_RIGHTPAREN;
(*sp)++;
break;
case '$':
kind = TK_DOLLAR;
(*sp)++;
break;
case '\'':
kind = TK_QDSTRING;
(*sp)++;
p = *sp;
while ( **sp != '\'' && **sp != '\0' )
(*sp)++;
if ( **sp == '\'' ) {
q = *sp;
res = malloc(q-p+1);
if ( !res ) {
kind = TK_OUTOFMEM;
} else {
strncpy(res,p,q-p);
res[q-p] = '\0';
*token_val = res;
}
(*sp)++;
} else {
kind = TK_NOENDQUOTE;
}
break;
default:
kind = TK_BAREWORD;
p = *sp;
while ( !isspace(**sp) && **sp != '\0' )
(*sp)++;
q = *sp;
res = malloc(q-p+1);
if ( !res ) {
kind = TK_OUTOFMEM;
} else {
strncpy(res,p,q-p);
res[q-p] = '\0';
*token_val = res;
}
break;
/* kind = TK_UNEXPCHAR; */
/* break; */
}
return kind;
}
/* Gobble optional whitespace */
static void
parse_whsp(char **sp)
{
while (isspace(**sp))
(*sp)++;
}
/* TBC:!!
* General note for all parsers: to guarantee the algorithm halts they
* must always advance the pointer even when an error is found. For
* this one is not that important since an error here is fatal at the
* upper layers, but it is a simple strategy that will not get in
* endless loops.
*/
/* Parse a sequence of dot-separated decimal strings */
static char *
parse_numericoid(char **sp, int *code)
{
char * res;
char * start = *sp;
int len;
/* Each iteration of this loops gets one decimal string */
while (**sp) {
if ( !isdigit(**sp) ) {
/* Initial char is not a digit or char after dot is not a digit */
*code = SCHEMA_ERR_NODIGIT;
return NULL;
}
(*sp)++;
while ( isdigit(**sp) )
(*sp)++;
if ( **sp != '.' )
break;
/* Otherwise, gobble the dot and loop again */
(*sp)++;
}
/* At this point, *sp points at the char past the numericoid. Perfect. */
len = *sp - start;
res = malloc(len+1);
if (!res) {
*code = SCHEMA_ERR_OUTOFMEM;
return(NULL);
}
strncpy(res,start,len);
res[len] = '\0';
return(res);
}
/* Parse a qdescr or a list of them enclosed in () */
static char **
parse_qdescrs(char **sp, int *code)
{
char ** res;
char ** res1;
int kind;
char * sval;
int size;
int pos;
parse_whsp(sp);
kind = get_token(sp,&sval);
if ( kind == TK_LEFTPAREN ) {
/* Let's presume there will be at least 2 entries */
size = 3;
res = calloc(3,sizeof(char *));
if ( !res ) {
*code = SCHEMA_ERR_OUTOFMEM;
return NULL;
}
pos = 0;
while (1) {
parse_whsp(sp);
kind = get_token(sp,&sval);
if ( kind == TK_RIGHTPAREN )
break;
if ( kind == TK_QDESCR ) {
if ( pos == size-2 ) {
size++;
res1 = realloc(res,size*sizeof(char *));
if ( !res1 ) {
charray_free(res);
*code = SCHEMA_ERR_OUTOFMEM;
return(NULL);
}
res = res1;
}
res[pos] = sval;
pos++;
parse_whsp(sp);
} else {
charray_free(res);
*code = SCHEMA_ERR_UNEXPTOKEN;
return(NULL);
}
}
res[pos] = NULL;
parse_whsp(sp);
return(res);
} else if ( kind == TK_QDESCR ) {
res = calloc(2,sizeof(char *));
if ( !res ) {
*code = SCHEMA_ERR_OUTOFMEM;
return NULL;
}
res[0] = sval;
res[1] = NULL;
parse_whsp(sp);
return res;
} else {
*code = SCHEMA_ERR_BADNAME;
return NULL;
}
}
/* Parse a woid or a $-separated list of them enclosed in () */
static char **
parse_oids(char **sp, int *code)
{
char ** res;
char ** res1;
int kind;
char * sval;
int size;
int pos;
/*
* Strictly speaking, doing this here accepts whsp before the
* ( at the begining of an oidlist, but his is harmless. Also,
* we are very liberal in what we accept as an OID. Maybe
* refine later.
*/
parse_whsp(sp);
kind = get_token(sp,&sval);
if ( kind == TK_LEFTPAREN ) {
/* Let's presume there will be at least 2 entries */
size = 3;
res = calloc(3,sizeof(char *));
if ( !res ) {
*code = SCHEMA_ERR_OUTOFMEM;
return NULL;
}
pos = 0;
parse_whsp(sp);
kind = get_token(sp,&sval);
if ( kind == TK_BAREWORD ) {
res[pos] = sval;
pos++;
} else {
*code = SCHEMA_ERR_UNEXPTOKEN;
charray_free(res);
return NULL;
}
parse_whsp(sp);
while (1) {
kind = get_token(sp,&sval);
if ( kind == TK_RIGHTPAREN )
break;
if ( kind == TK_DOLLAR ) {
parse_whsp(sp);
kind = get_token(sp,&sval);
if ( kind == TK_BAREWORD ) {
if ( pos == size-2 ) {
size++;
res1 = realloc(res,size*sizeof(char *));
if ( !res1 ) {
charray_free(res);
*code = SCHEMA_ERR_OUTOFMEM;
return(NULL);
}
res = res1;
}
res[pos] = sval;
pos++;
} else {
*code = SCHEMA_ERR_UNEXPTOKEN;
charray_free(res);
return NULL;
}
parse_whsp(sp);
} else {
*code = SCHEMA_ERR_UNEXPTOKEN;
charray_free(res);
return NULL;
}
}
res[pos] = NULL;
parse_whsp(sp);
return(res);
} else if ( kind == TK_BAREWORD ) {
res = calloc(2,sizeof(char *));
if ( !res ) {
*code = SCHEMA_ERR_OUTOFMEM;
return NULL;
}
res[0] = sval;
res[1] = NULL;
parse_whsp(sp);
return res;
} else {
*code = SCHEMA_ERR_BADNAME;
return NULL;
}
}
static void
free_oc(LDAP_OBJECT_CLASS * oc)
{
ldap_memfree(oc->oc_oid);
charray_free(oc->oc_names);
ldap_memfree(oc->oc_desc);
charray_free(oc->oc_sup_oids);
charray_free(oc->oc_at_oids_must);
charray_free(oc->oc_at_oids_may);
ldap_memfree(oc);
}
LDAP_OBJECT_CLASS *
ldap_str2objectclass( char * s, int * code, char ** errp )
{
int kind;
char * ss = s;
char * sval;
int seen_name = 0;
int seen_desc = 0;
int seen_obsolete = 0;
int seen_sup = 0;
int seen_kind = 0;
int seen_must = 0;
int seen_may = 0;
LDAP_OBJECT_CLASS * oc;
*errp = s;
oc = calloc(1,sizeof(LDAP_OBJECT_CLASS));
if ( !oc ) {
*code = SCHEMA_ERR_OUTOFMEM;
return NULL;
}
kind = get_token(&ss,&sval);
if ( kind != TK_LEFTPAREN ) {
*code = SCHEMA_ERR_NOLEFTPAREN;
free_oc(oc);
return NULL;
}
parse_whsp(&ss);
oc->oc_oid = parse_numericoid(&ss,code);
if ( !oc->oc_oid ) {
*errp = ss;
free_oc(oc);
return NULL;
}
parse_whsp(&ss);
/*
* Beyond this point we will be liberal an accept the items
* in any order.
*/
while (1) {
kind = get_token(&ss,&sval);
switch (kind) {
case TK_EOS:
*code = SCHEMA_ERR_NORIGHTPAREN;
*errp = ss;
free_oc(oc);
return NULL;
case TK_RIGHTPAREN:
return oc;
case TK_BAREWORD:
if ( !strcmp(sval,"NAME") ) {
if ( seen_name ) {
*code = SCHEMA_ERR_DUPOPT;
*errp = ss;
free_oc(oc);
return(NULL);
}
seen_name = 1;
oc->oc_names = parse_qdescrs(&ss,code);
if ( !oc->oc_names ) {
if ( *code != SCHEMA_ERR_OUTOFMEM )
*code = SCHEMA_ERR_BADNAME;
*errp = ss;
free_oc(oc);
return NULL;
}
} else if ( !strcmp(sval,"DESC") ) {
if ( seen_desc ) {
*code = SCHEMA_ERR_DUPOPT;
*errp = ss;
free_oc(oc);
return(NULL);
}
seen_desc = 1;
parse_whsp(&ss);
kind = get_token(&ss,&sval);
if ( kind != TK_QDSTRING ) {
*code = SCHEMA_ERR_UNEXPTOKEN;
*errp = ss;
free(oc);
return NULL;
}
oc->oc_desc = sval;
parse_whsp(&ss);
} else if ( !strcmp(sval,"OBSOLETE") ) {
if ( seen_obsolete ) {
*code = SCHEMA_ERR_DUPOPT;
*errp = ss;
free_oc(oc);
return(NULL);
}
seen_obsolete = 1;
oc->oc_obsolete = 1;
parse_whsp(&ss);
} else if ( !strcmp(sval,"SUP") ) {
if ( seen_sup ) {
*code = SCHEMA_ERR_DUPOPT;
*errp = ss;
free_oc(oc);
return(NULL);
}
seen_sup = 1;
/* Netscape DS is broken or I have not
understood the syntax. */
/* oc->oc_sup_oids = parse_oids(&ss,code); */
oc->oc_sup_oids = parse_qdescrs(&ss,code);
if ( !oc->oc_sup_oids ) {
*errp = ss;
free_oc(oc);
return NULL;
}
} else if ( !strcmp(sval,"ABSTRACT") ) {
if ( seen_kind ) {
*code = SCHEMA_ERR_DUPOPT;
*errp = ss;
free_oc(oc);
return(NULL);
}
seen_kind = 1;
oc->oc_kind = 0;
parse_whsp(&ss);
} else if ( !strcmp(sval,"STRUCTURAL") ) {
if ( seen_kind ) {
*code = SCHEMA_ERR_DUPOPT;
*errp = ss;
free_oc(oc);
return(NULL);
}
seen_kind = 1;
oc->oc_kind = 1;
parse_whsp(&ss);
} else if ( !strcmp(sval,"AUXILIARY") ) {
if ( seen_kind ) {
*code = SCHEMA_ERR_DUPOPT;
*errp = ss;
free_oc(oc);
return(NULL);
}
seen_kind = 1;
oc->oc_kind = 2;
parse_whsp(&ss);
} else if ( !strcmp(sval,"MUST") ) {
if ( seen_must ) {
*code = SCHEMA_ERR_DUPOPT;
*errp = ss;
free_oc(oc);
return(NULL);
}
seen_must = 1;
oc->oc_at_oids_must = parse_oids(&ss,code);
if ( !oc->oc_at_oids_must ) {
*errp = ss;
free_oc(oc);
return NULL;
}
parse_whsp(&ss);
} else if ( !strcmp(sval,"MAY") ) {
if ( seen_may ) {
*code = SCHEMA_ERR_DUPOPT;
*errp = ss;
free_oc(oc);
return(NULL);
}
seen_may = 1;
oc->oc_at_oids_may = parse_oids(&ss,code);
if ( !oc->oc_at_oids_may ) {
*errp = ss;
free_oc(oc);
return NULL;
}
parse_whsp(&ss);
} else {
*code = SCHEMA_ERR_UNEXPTOKEN;
*errp = ss;
free_oc(oc);
return NULL;
}
break;
default:
*code = SCHEMA_ERR_UNEXPTOKEN;
*errp = ss;
free_oc(oc);
return NULL;
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment