mirror of
https://github.com/samba-team/samba.git
synced 2025-01-13 13:18:06 +03:00
26af14c39b
Applications that use LDB modules will now have to run ldb_global_init()
before they can use LDB.
The next step will be adding support for loading LDB modules from .so
files. This will also allow us to use one LDB without difference between the
standalone and the Samba-specific build
(This used to be commit 52a2356505
)
629 lines
13 KiB
C
629 lines
13 KiB
C
/*
|
|
ldb database library
|
|
|
|
Copyright (C) Simo Sorce 2005
|
|
|
|
** NOTE! The following LGPL license applies to the ldb
|
|
** library. This does NOT imply that all of Samba is released
|
|
** under the LGPL
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library 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
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/*
|
|
* Name: ldb
|
|
*
|
|
* Component: ldbdel
|
|
*
|
|
* Description: utility to delete records - modelled on ldapdelete
|
|
*
|
|
* Author: Andrew Tridgell
|
|
*/
|
|
|
|
#include "includes.h"
|
|
#include "ldb/include/includes.h"
|
|
#include "ldb/tools/cmdline.h"
|
|
|
|
#define SCHEMA_UNKNOWN 0
|
|
#define SCHEMA_NAME 1
|
|
#define SCHEMA_SUP 2
|
|
#define SCHEMA_STRUCTURAL 3
|
|
#define SCHEMA_ABSTRACT 4
|
|
#define SCHEMA_AUXILIARY 5
|
|
#define SCHEMA_MUST 6
|
|
#define SCHEMA_MAY 7
|
|
#define SCHEMA_SINGLE_VALUE 8
|
|
#define SCHEMA_EQUALITY 9
|
|
#define SCHEMA_ORDERING 10
|
|
#define SCHEMA_SUBSTR 11
|
|
#define SCHEMA_SYNTAX 12
|
|
#define SCHEMA_DESC 13
|
|
|
|
struct syntax_map {
|
|
const char *Standard_OID;
|
|
const char *AD_OID;
|
|
const char *comment;
|
|
} syntax_map[] = {
|
|
{ "1.3.6.1.4.1.1466.115.121.1.12", "2.5.5.1", "Object(DS-DN) == a DN" },
|
|
{ "1.3.6.1.4.1.1466.115.121.1.38", "2.5.5.2", "OID String" },
|
|
{ "1.2.840.113556.1.4.905", "2.5.5.4", "Case Insensitive String" },
|
|
{ "1.3.6.1.4.1.1466.115.121.1.44", "2.5.5.5", "Printable String" },
|
|
{ "1.3.6.1.4.1.1466.115.121.1.36", "2.5.5.6", "Numeric String" },
|
|
{ "1.2.840.113556.1.4.903", "2.5.5.7", "OctetString: Binary+DN" },
|
|
{ "1.3.6.1.4.1.1466.115.121.1.7", "2.5.5.8", "Boolean" },
|
|
{ "1.3.6.1.4.1.1466.115.121.1.27", "2.5.5.9", "Integer" },
|
|
{ "1.3.6.1.4.1.1466.115.121.1.40", "2.5.5.10", "Octet String" },
|
|
{ "1.3.6.1.4.1.1466.115.121.1.24", "2.5.5.11", "Generalized Time" },
|
|
{ "1.3.6.1.4.1.1466.115.121.1.53", "2.5.5.11", "UTC Time" },
|
|
{ "1.3.6.1.4.1.1466.115.121.1.15", "2.5.5.12", "Directory String" },
|
|
{ "1.3.6.1.4.1.1466.115.121.1.43", "2.5.5.13", "Presentation Address" },
|
|
{ "Not Found Yet", "2.5.5.14", "OctetString: String+DN" },
|
|
{ "1.2.840.113556.1.4.907", "2.5.5.15", "NT Security Descriptor" },
|
|
{ "1.2.840.113556.1.4.906", "2.5.5.16", "Interval" },
|
|
{ "1.3.6.1.4.1.1466.115.121.1.40", "2.5.5.17", "Octet String - Security Identifier (SID)" },
|
|
{ "1.3.6.1.4.1.1466.115.121.1.26", "2.5.5.5", "IA5 String" },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
|
|
struct schema_conv {
|
|
int count;
|
|
int failures;
|
|
};
|
|
|
|
struct token {
|
|
int type;
|
|
char *value;
|
|
};
|
|
|
|
struct ldb_context *ldb_ctx;
|
|
struct ldb_dn *basedn;
|
|
|
|
static int check_braces(const char *string)
|
|
{
|
|
int b;
|
|
char *c;
|
|
|
|
b = 0;
|
|
if ((c = strchr(string, '(')) == NULL) {
|
|
return -1;
|
|
}
|
|
b++;
|
|
c++;
|
|
while (b) {
|
|
c = strpbrk(c, "()");
|
|
if (c == NULL) return 1;
|
|
if (*c == '(') b++;
|
|
if (*c == ')') b--;
|
|
c++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static char *skip_spaces(char *string) {
|
|
return (string + strspn(string, " \t\n"));
|
|
}
|
|
|
|
static int add_multi_string(struct ldb_message *msg, const char *attr, char *values)
|
|
{
|
|
char *c;
|
|
char *s;
|
|
int n;
|
|
|
|
c = skip_spaces(values);
|
|
while (*c) {
|
|
n = strcspn(c, " \t$");
|
|
s = talloc_strndup(msg, c, n);
|
|
if (ldb_msg_add_string(msg, attr, s) != 0) {
|
|
return -1;
|
|
}
|
|
c += n;
|
|
c += strspn(c, " \t$");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define MSG_ADD_STRING(a, v) do { if (ldb_msg_add_string(msg, a, v) != 0) goto failed; } while(0)
|
|
#define MSG_ADD_M_STRING(a, v) do { if (add_multi_string(msg, a, v) != 0) goto failed; } while(0)
|
|
|
|
static char *get_def_value(TALLOC_CTX *ctx, char **string)
|
|
{
|
|
char *c = *string;
|
|
char *value;
|
|
int n;
|
|
|
|
if (*c == '\'') {
|
|
c++;
|
|
n = strcspn(c, "\'");
|
|
value = talloc_strndup(ctx, c, n);
|
|
c += n;
|
|
c++; /* skip closing \' */
|
|
} else {
|
|
n = strcspn(c, " \t\n");
|
|
value = talloc_strndup(ctx, c, n);
|
|
c += n;
|
|
}
|
|
*string = c;
|
|
|
|
return value;
|
|
}
|
|
|
|
static struct token *get_next_schema_token(TALLOC_CTX *ctx, char **string)
|
|
{
|
|
char *c = skip_spaces(*string);
|
|
char *type;
|
|
struct token *token;
|
|
int n;
|
|
|
|
token = talloc(ctx, struct token);
|
|
|
|
n = strcspn(c, " \t\n");
|
|
type = talloc_strndup(token, c, n);
|
|
c += n;
|
|
c = skip_spaces(c);
|
|
|
|
if (strcasecmp("NAME", type) == 0) {
|
|
talloc_free(type);
|
|
token->type = SCHEMA_NAME;
|
|
/* we do not support aliases so we get only the first name given and skip others */
|
|
if (*c == '(') {
|
|
char *s = strchr(c, ')');
|
|
if (s == NULL) return NULL;
|
|
s = skip_spaces(s);
|
|
*string = s;
|
|
|
|
c++;
|
|
c = skip_spaces(c);
|
|
}
|
|
|
|
token->value = get_def_value(ctx, &c);
|
|
|
|
if (*string < c) { /* single name */
|
|
c = skip_spaces(c);
|
|
*string = c;
|
|
}
|
|
return token;
|
|
}
|
|
if (strcasecmp("SUP", type) == 0) {
|
|
talloc_free(type);
|
|
token->type = SCHEMA_SUP;
|
|
|
|
if (*c == '(') {
|
|
c++;
|
|
n = strcspn(c, ")");
|
|
token->value = talloc_strndup(ctx, c, n);
|
|
c += n;
|
|
c++;
|
|
} else {
|
|
token->value = get_def_value(ctx, &c);
|
|
}
|
|
|
|
c = skip_spaces(c);
|
|
*string = c;
|
|
return token;
|
|
}
|
|
|
|
if (strcasecmp("STRUCTURAL", type) == 0) {
|
|
talloc_free(type);
|
|
token->type = SCHEMA_STRUCTURAL;
|
|
*string = c;
|
|
return token;
|
|
}
|
|
|
|
if (strcasecmp("ABSTRACT", type) == 0) {
|
|
talloc_free(type);
|
|
token->type = SCHEMA_ABSTRACT;
|
|
*string = c;
|
|
return token;
|
|
}
|
|
|
|
if (strcasecmp("AUXILIARY", type) == 0) {
|
|
talloc_free(type);
|
|
token->type = SCHEMA_AUXILIARY;
|
|
*string = c;
|
|
return token;
|
|
}
|
|
|
|
if (strcasecmp("MUST", type) == 0) {
|
|
talloc_free(type);
|
|
token->type = SCHEMA_MUST;
|
|
|
|
if (*c == '(') {
|
|
c++;
|
|
n = strcspn(c, ")");
|
|
token->value = talloc_strndup(ctx, c, n);
|
|
c += n;
|
|
c++;
|
|
} else {
|
|
token->value = get_def_value(ctx, &c);
|
|
}
|
|
|
|
c = skip_spaces(c);
|
|
*string = c;
|
|
return token;
|
|
}
|
|
|
|
if (strcasecmp("MAY", type) == 0) {
|
|
talloc_free(type);
|
|
token->type = SCHEMA_MAY;
|
|
|
|
if (*c == '(') {
|
|
c++;
|
|
n = strcspn(c, ")");
|
|
token->value = talloc_strndup(ctx, c, n);
|
|
c += n;
|
|
c++;
|
|
} else {
|
|
token->value = get_def_value(ctx, &c);
|
|
}
|
|
|
|
c = skip_spaces(c);
|
|
*string = c;
|
|
return token;
|
|
}
|
|
|
|
if (strcasecmp("SINGLE-VALUE", type) == 0) {
|
|
talloc_free(type);
|
|
token->type = SCHEMA_SINGLE_VALUE;
|
|
*string = c;
|
|
return token;
|
|
}
|
|
|
|
if (strcasecmp("EQUALITY", type) == 0) {
|
|
talloc_free(type);
|
|
token->type = SCHEMA_EQUALITY;
|
|
|
|
token->value = get_def_value(ctx, &c);
|
|
|
|
c = skip_spaces(c);
|
|
*string = c;
|
|
return token;
|
|
}
|
|
|
|
if (strcasecmp("ORDERING", type) == 0) {
|
|
talloc_free(type);
|
|
token->type = SCHEMA_ORDERING;
|
|
|
|
token->value = get_def_value(ctx, &c);
|
|
|
|
c = skip_spaces(c);
|
|
*string = c;
|
|
return token;
|
|
}
|
|
|
|
if (strcasecmp("SUBSTR", type) == 0) {
|
|
talloc_free(type);
|
|
token->type = SCHEMA_SUBSTR;
|
|
|
|
token->value = get_def_value(ctx, &c);
|
|
|
|
c = skip_spaces(c);
|
|
*string = c;
|
|
return token;
|
|
}
|
|
|
|
if (strcasecmp("SYNTAX", type) == 0) {
|
|
talloc_free(type);
|
|
token->type = SCHEMA_SYNTAX;
|
|
|
|
token->value = get_def_value(ctx, &c);
|
|
|
|
c = skip_spaces(c);
|
|
*string = c;
|
|
return token;
|
|
}
|
|
|
|
if (strcasecmp("DESC", type) == 0) {
|
|
talloc_free(type);
|
|
token->type = SCHEMA_DESC;
|
|
|
|
token->value = get_def_value(ctx, &c);
|
|
|
|
c = skip_spaces(c);
|
|
*string = c;
|
|
return token;
|
|
}
|
|
|
|
token->type = SCHEMA_UNKNOWN;
|
|
token->value = type;
|
|
if (*c == ')') {
|
|
*string = c;
|
|
return token;
|
|
}
|
|
if (*c == '\'') {
|
|
c = strchr(++c, '\'');
|
|
c++;
|
|
} else {
|
|
c += strcspn(c, " \t\n");
|
|
}
|
|
c = skip_spaces(c);
|
|
*string = c;
|
|
|
|
return token;
|
|
}
|
|
|
|
static struct ldb_message *process_entry(TALLOC_CTX *mem_ctx, const char *entry)
|
|
{
|
|
TALLOC_CTX *ctx;
|
|
struct ldb_message *msg;
|
|
struct token *token;
|
|
char *c, *s;
|
|
int n;
|
|
|
|
ctx = talloc_new(mem_ctx);
|
|
msg = ldb_msg_new(ctx);
|
|
|
|
ldb_msg_add_string(msg, "objectClass", "top");
|
|
|
|
c = talloc_strdup(ctx, entry);
|
|
if (!c) return NULL;
|
|
|
|
c = skip_spaces(c);
|
|
|
|
switch (*c) {
|
|
case 'a':
|
|
if (strncmp(c, "attributetype", 13) == 0) {
|
|
c += 13;
|
|
MSG_ADD_STRING("objectClass", "attributeSchema");
|
|
break;
|
|
}
|
|
goto failed;
|
|
case 'o':
|
|
if (strncmp(c, "objectclass", 11) == 0) {
|
|
c += 11;
|
|
MSG_ADD_STRING("objectClass", "classSchema");
|
|
break;
|
|
}
|
|
goto failed;
|
|
default:
|
|
goto failed;
|
|
}
|
|
|
|
c = strchr(c, '(');
|
|
if (c == NULL) goto failed;
|
|
c++;
|
|
|
|
c = skip_spaces(c);
|
|
|
|
/* get attributeID */
|
|
n = strcspn(c, " \t");
|
|
s = talloc_strndup(msg, c, n);
|
|
MSG_ADD_STRING("attributeID", s);
|
|
c += n;
|
|
c = skip_spaces(c);
|
|
|
|
while (*c != ')') {
|
|
token = get_next_schema_token(msg, &c);
|
|
if (!token) goto failed;
|
|
|
|
switch (token->type) {
|
|
case SCHEMA_NAME:
|
|
MSG_ADD_STRING("cn", token->value);
|
|
MSG_ADD_STRING("name", token->value);
|
|
MSG_ADD_STRING("lDAPDisplayName", token->value);
|
|
msg->dn = ldb_dn_string_compose(msg, basedn,
|
|
"CN=%s,CN=Schema,CN=Configuration",
|
|
token->value);
|
|
break;
|
|
|
|
case SCHEMA_SUP:
|
|
MSG_ADD_M_STRING("subClassOf", token->value);
|
|
break;
|
|
|
|
case SCHEMA_STRUCTURAL:
|
|
MSG_ADD_STRING("objectClassCategory", "1");
|
|
break;
|
|
|
|
case SCHEMA_ABSTRACT:
|
|
MSG_ADD_STRING("objectClassCategory", "2");
|
|
break;
|
|
|
|
case SCHEMA_AUXILIARY:
|
|
MSG_ADD_STRING("objectClassCategory", "3");
|
|
break;
|
|
|
|
case SCHEMA_MUST:
|
|
MSG_ADD_M_STRING("mustContain", token->value);
|
|
break;
|
|
|
|
case SCHEMA_MAY:
|
|
MSG_ADD_M_STRING("mayContain", token->value);
|
|
break;
|
|
|
|
case SCHEMA_SINGLE_VALUE:
|
|
MSG_ADD_STRING("isSingleValued", "TRUE");
|
|
break;
|
|
|
|
case SCHEMA_EQUALITY:
|
|
/* TODO */
|
|
break;
|
|
|
|
case SCHEMA_ORDERING:
|
|
/* TODO */
|
|
break;
|
|
|
|
case SCHEMA_SUBSTR:
|
|
/* TODO */
|
|
break;
|
|
|
|
case SCHEMA_SYNTAX:
|
|
MSG_ADD_STRING("attributeSyntax", token->value);
|
|
break;
|
|
|
|
case SCHEMA_DESC:
|
|
MSG_ADD_STRING("description", token->value);
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, "Unknown Definition: %s\n", token->value);
|
|
}
|
|
}
|
|
|
|
talloc_steal(mem_ctx, msg);
|
|
talloc_free(ctx);
|
|
return msg;
|
|
|
|
failed:
|
|
talloc_free(ctx);
|
|
return NULL;
|
|
}
|
|
|
|
static struct schema_conv process_file(FILE *in, FILE *out)
|
|
{
|
|
TALLOC_CTX *ctx;
|
|
struct schema_conv ret;
|
|
char *entry;
|
|
int c, t, line;
|
|
struct ldb_ldif ldif;
|
|
|
|
ldif.changetype = LDB_CHANGETYPE_NONE;
|
|
|
|
ctx = talloc_new(NULL);
|
|
|
|
ret.count = 0;
|
|
ret.failures = 0;
|
|
line = 0;
|
|
|
|
while ((c = fgetc(in)) != EOF) {
|
|
line++;
|
|
/* fprintf(stderr, "Parsing line %d\n", line); */
|
|
if (c == '#') {
|
|
do {
|
|
c = fgetc(in);
|
|
} while (c != EOF && c != '\n');
|
|
continue;
|
|
}
|
|
if (c == '\n') {
|
|
continue;
|
|
}
|
|
|
|
t = 0;
|
|
entry = talloc_array(ctx, char, 1024);
|
|
if (entry == NULL) exit(-1);
|
|
|
|
do {
|
|
if (c == '\n') {
|
|
entry[t] = '\0';
|
|
if (check_braces(entry) == 0) {
|
|
ret.count++;
|
|
ldif.msg = process_entry(ctx, entry);
|
|
if (ldif.msg == NULL) {
|
|
ret.failures++;
|
|
fprintf(stderr, "No valid msg from entry \n[%s]\n at line %d\n", entry, line);
|
|
break;
|
|
}
|
|
ldb_ldif_write_file(ldb_ctx, out, &ldif);
|
|
break;
|
|
}
|
|
line++;
|
|
} else {
|
|
entry[t] = c;
|
|
t++;
|
|
}
|
|
if ((t % 1023) == 0) {
|
|
entry = talloc_realloc(ctx, entry, char, t + 1024);
|
|
if (entry == NULL) exit(-1);
|
|
}
|
|
} while ((c = fgetc(in)) != EOF);
|
|
|
|
if (c != '\n') {
|
|
entry[t] = '\0';
|
|
if (check_braces(entry) == 0) {
|
|
ret.count++;
|
|
ldif.msg = process_entry(ctx, entry);
|
|
if (ldif.msg == NULL) {
|
|
ret.failures++;
|
|
fprintf(stderr, "No valid msg from entry \n[%s]\n at line %d\n", entry, line);
|
|
break;
|
|
}
|
|
ldb_ldif_write_file(ldb_ctx, out, &ldif);
|
|
} else {
|
|
fprintf(stderr, "malformed entry on line %d\n", line);
|
|
ret.failures++;
|
|
}
|
|
}
|
|
|
|
if (c == EOF) break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void usage(void)
|
|
{
|
|
printf("Usage: oLschema2ldif <options>\n");
|
|
printf("Options:\n");
|
|
printf(" -I inputfile inputfile otherwise STDIN\n");
|
|
printf(" -O outputfile outputfile otherwise STDOUT\n");
|
|
printf(" -o options pass options like modules to activate\n");
|
|
printf(" e.g: -o modules:timestamps\n");
|
|
printf("\n");
|
|
printf("Converts records from an openLdap formatted schema to an ldif schema\n\n");
|
|
exit(1);
|
|
}
|
|
|
|
int main(int argc, const char **argv)
|
|
{
|
|
TALLOC_CTX *ctx;
|
|
struct schema_conv ret;
|
|
struct ldb_cmdline *options;
|
|
FILE *in = stdin;
|
|
FILE *out = stdout;
|
|
|
|
ldb_global_init();
|
|
|
|
ctx = talloc_new(NULL);
|
|
ldb_ctx = ldb_init(ctx);
|
|
|
|
setenv("LDB_URL", "NONE", 1);
|
|
options = ldb_cmdline_process(ldb_ctx, argc, argv, usage);
|
|
|
|
if (options->basedn == NULL) {
|
|
perror("Base DN not specified");
|
|
exit(1);
|
|
} else {
|
|
basedn = ldb_dn_explode(ctx, options->basedn);
|
|
if (basedn == NULL) {
|
|
perror("Malformed Base DN");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (options->input) {
|
|
in = fopen(options->input, "r");
|
|
if (!in) {
|
|
perror(options->input);
|
|
exit(1);
|
|
}
|
|
}
|
|
if (options->output) {
|
|
out = fopen(options->output, "w");
|
|
if (!out) {
|
|
perror(options->output);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
ret = process_file(in, out);
|
|
|
|
fclose(in);
|
|
fclose(out);
|
|
|
|
printf("Converted %d records with %d failures\n", ret.count, ret.failures);
|
|
|
|
return 0;
|
|
}
|