diff options
Diffstat (limited to 'ldap/servers/slapd/back-ldif')
| -rw-r--r-- | ldap/servers/slapd/back-ldif/Makefile | 81 | ||||
| -rw-r--r-- | ldap/servers/slapd/back-ldif/add.c | 189 | ||||
| -rw-r--r-- | ldap/servers/slapd/back-ldif/back-ldif.h | 94 | ||||
| -rw-r--r-- | ldap/servers/slapd/back-ldif/bind.c | 108 | ||||
| -rw-r--r-- | ldap/servers/slapd/back-ldif/close.c | 79 | ||||
| -rw-r--r-- | ldap/servers/slapd/back-ldif/compare.c | 82 | ||||
| -rw-r--r-- | ldap/servers/slapd/back-ldif/config.c | 203 | ||||
| -rw-r--r-- | ldap/servers/slapd/back-ldif/delete.c | 136 | ||||
| -rw-r--r-- | ldap/servers/slapd/back-ldif/dllmain.c | 132 | ||||
| -rw-r--r-- | ldap/servers/slapd/back-ldif/init.c | 114 | ||||
| -rw-r--r-- | ldap/servers/slapd/back-ldif/libback-ldif.def | 12 | ||||
| -rw-r--r-- | ldap/servers/slapd/back-ldif/modify.c | 557 | ||||
| -rw-r--r-- | ldap/servers/slapd/back-ldif/modrdn.c | 282 | ||||
| -rw-r--r-- | ldap/servers/slapd/back-ldif/monitor.c | 124 | ||||
| -rw-r--r-- | ldap/servers/slapd/back-ldif/search.c | 197 | ||||
| -rw-r--r-- | ldap/servers/slapd/back-ldif/start.c | 31 | ||||
| -rw-r--r-- | ldap/servers/slapd/back-ldif/unbind.c | 27 |
17 files changed, 2448 insertions, 0 deletions
diff --git a/ldap/servers/slapd/back-ldif/Makefile b/ldap/servers/slapd/back-ldif/Makefile new file mode 100644 index 00000000..1b7037cd --- /dev/null +++ b/ldap/servers/slapd/back-ldif/Makefile @@ -0,0 +1,81 @@ +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +# +# GNU Makefile for LDAP Back-ldif backend +# + +LDAP_SRC = ../../.. +MCOM_ROOT = ../../../../.. + +NOSTDCLEAN=true # don't let nsconfig.mk define target clean +NOSTDSTRIP=true # don't let nsconfig.mk define target strip +NSPR20=true # probably should be defined somewhere else (not sure where) + +OBJDEST = $(OBJDIR)/lib/libback-ldif +LIBDIR = $(LDAP_LIBDIR) +SERVER_OBJDEST = $(OBJDIR)/servers/obj + +include $(MCOM_ROOT)/ldapserver/nsdefs.mk +include $(MCOM_ROOT)/ldapserver/nsconfig.mk +include $(LDAP_SRC)/nsldap.mk + +BACKLDIF_OBJS = close.o delete.o modrdn.o unbind.o add.o \ + compare.o init.o search.o bind.o config.o modify.o monitor.o \ + start.o + +OBJS = $(addprefix $(OBJDEST)/, $(BACKLDIF_OBJS)) + +SERVER_OBJS= ch_malloc.o entry.o result.o modutil.o + +EXTRA_OBJS = $(addprefix $(SERVER_OBJDEST)/, $(SERVER_OBJS)) + +INCLUDES += -I.. + +ifeq ($(ARCH), WINNT) +BACKLDIF_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o) +endif + +LDAP_BACKLDIF= $(addprefix $(LIBDIR)/, $(LIBBACK_LDIF_DLL).$(DLL_SUFFIX)) + +ifeq ($(ARCH), WINNT) +EXTRA_LIBS_DEP += $(LIBSECURITY) $(LIBNSPR) \ + $(LDAP_COMMON_LIBS_DEP) $(LDAP_SDK_LIBS_DEP) \ + $(LIBSLAPD_DEP) $(LIBLDAPU_DEP) + +EXTRA_LIBS += $(LIBSECURITY) $(LIBNSPR) \ + $(LDAP_COMMON_LIBS) $(LDAP_SDK_LIBS) \ + $(LIBSLAPD) $(THREADSLIB) $(LIBLDAPU) +endif + +ifeq ($(ARCH), AIX) +EXTRA_LIBS += $(DLL_EXTRA_LIBS) +endif + +clientSDK: + +all: $(OBJDEST) $(LIBDIR) $(LDAP_BACKLDIF) + +$(LIBDIR): + $(MKDIR) $(LIBDIR) + +$(LDAP_BACKLDIF): $(OBJS) $(BACKLDIF_DLL_OBJ) + $(LINK_DLL) $(BACKLDIF_DLL_OBJ) $(EXTRA_LIBS) + +$(SERVER_OBJDEST)/ch_malloc.o: ../ch_malloc.c + $(CC) -c $(CFLAGS) $(MCC_INCLUDE) $< $(OFFLAG)$*.o + +clean: + $(RM) $(OBJS) +ifeq ($(ARCH), WINNT) + $(RM) $(BACKLDIF_DLL_OBJ) +endif + $(RM) $(LDAP_BACKLDIF) + +$(OBJDEST): + $(MKDIR) $(OBJDEST) + diff --git a/ldap/servers/slapd/back-ldif/add.c b/ldap/servers/slapd/back-ldif/add.c new file mode 100644 index 00000000..cd0b81dc --- /dev/null +++ b/ldap/servers/slapd/back-ldif/add.c @@ -0,0 +1,189 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * File: add.c + * + * Functions: + * + * ldif_back_add() - ldap ldif back-end add routine + * ldifentry_init() - takes an Entry and makes an ldif_Entry + * + */ + +#include "back-ldif.h" +ldif_Entry * ldifentry_init(Slapi_Entry *); + +/* + * Function: ldif_back_add + * + * Returns: returns 0 if good, -1 else. + * + * Description: For changetype: add, this function adds the entry + */ +int +ldif_back_add( Slapi_PBlock *pb ) +{ + LDIF *db; /*Stores the ldif database*/ + char *dn = NULL, *parentdn = NULL; + Slapi_Entry *e; /*The new entry to add*/ + ldif_Entry *new, *old; /*Used for various accounting purposes*/ + ldif_Entry *prev; /*Used to add new ldif_Entry to db*/ + ldif_Entry *tprev; /*Dummy pointer for traversing the list*/ + char *errbuf = NULL; + + prev = NULL; + tprev = NULL; + + /*Turn on tracing to see this printed out*/ + LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_add\n", 0, 0, 0 ); + + /*Get the database, the dn and the entry to add*/ + if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db ) < 0 || + slapi_pblock_get( pb, SLAPI_ADD_TARGET, &dn ) < 0 || + slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &e ) < 0){ + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + } + + /*Check to make sure the entry passes the schema check*/ + if ( slapi_entry_schema_check( pb, e ) != 0 ) { + LDAPDebug( LDAP_DEBUG_TRACE, "entry failed schema check\n", 0, 0, 0 ); + slapi_send_ldap_result( pb, LDAP_OBJECT_CLASS_VIOLATION, NULL, NULL, 0, NULL ); + return( -1 ); + } + + prev = NULL; + + /*Lock the database*/ + PR_Lock( db->ldif_lock ); + + /* + * Attempt to find this dn in db. If there is no such dn, + * ldif_find_entry should return NULL, and prev should point + * to the last element in the list. + */ + if ((old = (ldif_Entry *)ldif_find_entry(pb, db, dn, &prev)) != NULL) { + + /* + * If we've reached this code, there is an entry in db + * whose dn matches dn, so release the db lock, + * tell the user and return + */ + PR_Unlock( db->ldif_lock ); + slapi_send_ldap_result( pb, LDAP_ALREADY_EXISTS, NULL, NULL, 0, NULL ); + return( -1 ); + } + + + /* + * Get the parent dn and see if the corresponding entry exists. + * If the parent does not exist, only allow the "root" user to + * add the entry. + */ + if ( (parentdn = slapi_dn_beparent( pb, dn )) != NULL ) { + int rc; + if ((old = (ldif_Entry *)ldif_find_entry( pb, db, parentdn, &tprev)) == NULL ) { + slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL ); + LDAPDebug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0, 0, 0 ); + goto error_return; + } + rc= slapi_access_allowed( pb, e, NULL, NULL, SLAPI_ACL_ADD ); + if ( rc!=LDAP_SUCCESS ) { + LDAPDebug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,0, 0 ); + slapi_send_ldap_result( pb, rc, NULL, NULL, 0, NULL ); + goto error_return; + } + } else { /* no parent */ + int isroot; + slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot ); + if ( !isroot ) { + LDAPDebug( LDAP_DEBUG_TRACE, "no parent & not root\n", 0, 0, 0 ); + slapi_send_ldap_result( pb, LDAP_INSUFFICIENT_ACCESS, NULL, NULL, 0, NULL ); + goto error_return; + } + + } + + /* + * Before we add the entry, find out if the syntax of the aci + * aci attribute values are correct or not. We don't want to add + * the entry if the syntax is incorrect. + */ + if ( slapi_acl_verify_aci_syntax(pb, e, &errbuf) != 0 ) { + slapi_send_ldap_result( pb, LDAP_INVALID_SYNTAX, NULL, errbuf, 0, NULL ); + if (errbuf) free(errbuf); + goto error_return; + } + + /*Make a new element for the linked list*/ + if ( (new = (ldif_Entry *)ldifentry_init( e )) == NULL){ + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + goto error_return; + + } + + /*Add the new element to the end of the list of entries in db*/ + if ( update_db(pb, db, new, prev, LDIF_DB_ADD) != 0) + { + ldifentry_free( new ); + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + goto error_return; + + } + + /*We have been sucessful. Tell the user*/ + slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL ); + + /*Release the database lock*/ + PR_Unlock( db->ldif_lock ); + + /*Free the parentdn, and return*/ + if ( parentdn != NULL ){ + free( (void *)parentdn ); + } + LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_add\n", 0, 0, 0 ); + return( 0 ); + + error_return:; + if ( parentdn != NULL ){ + free( (void *)parentdn ); + } + + PR_Unlock( db->ldif_lock ); + return( -1 ); +} + +/* + * Function: ldifentry_init + * + * Returns: a pointer to an ldif_Entry, or NULL + * + * Description: Takes a pointer to an Entry, and sticks + * it into an ldif_Entry structure. + * Note, uses Malloc. + */ +ldif_Entry * +ldifentry_init(Slapi_Entry *e) +{ + ldif_Entry *new; + + /*Alloc a new ldif_entry*/ + new = (ldif_Entry *) malloc(sizeof(ldif_Entry)); + + /*Did it work? if not, return NULL*/ + if (new == NULL) { + return (NULL); + } + /*If it did work, then fill it*/ + new->lde_e = e; + new->next = NULL; + + /*Send it*/ + return (new); +} + + + diff --git a/ldap/servers/slapd/back-ldif/back-ldif.h b/ldap/servers/slapd/back-ldif/back-ldif.h new file mode 100644 index 00000000..5875c985 --- /dev/null +++ b/ldap/servers/slapd/back-ldif/back-ldif.h @@ -0,0 +1,94 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * File: back-ldif.h + * + * Description: This header file contains the definitions + * for the data structures used in the ldif backend database + */ + +#define SLAPD_LOGGING 1 + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> + +/* include NSPR header files */ +#include "prlock.h" + +#include "ldaplog.h" +#include "portable.h" +#include "dirver.h" +#include "slap.h" + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#else +#include <sys/socket.h> +#endif /* _WIN32 */ + +/*Defines*/ +#define LDIF_DB_ADD 0 +#define LDIF_DB_DELETE 1 +#define LDIF_DB_REPLACE 2 + + +/*This structure basically allows the entries to be linked listed*/ +struct ldif_entry{ + Slapi_Entry *lde_e; /*ptr to the Entry datatype, but you knew that*/ + struct ldif_entry *next; /*ptr to the next list element.*/ +}; +typedef struct ldif_entry ldif_Entry; + + +/*Holds the data from the ldif file*/ +struct ldif { + long ldif_n; /*The number of entries in the database*/ + long ldif_tries; /*The number of accesses to the database*/ + long ldif_hits; /*The number of succesful searches to the db*/ + char *ldif_file; /*From where we read the ldif data*/ + PRLock *ldif_lock; /*Write & read lock.(a simple locking model)*/ + ldif_Entry *ldif_entries; /*The linked list of entries*/ +}; +typedef struct ldif LDIF; + + +/*Prototypes*/ + int ldif_back_modify( Slapi_PBlock * ); + int update_db(Slapi_PBlock *, LDIF *, ldif_Entry *, ldif_Entry *, int); + int db2disk(Slapi_PBlock *, LDIF *); + void ldifentry_free(ldif_Entry *); + ldif_Entry *ldifentry_dup(ldif_Entry *); + ldif_Entry *ldif_find_entry(Slapi_PBlock *, LDIF *, char *, ldif_Entry **); + int apply_mods( Slapi_Entry *, LDAPMod ** ); + + int ldif_back_add( Slapi_PBlock *); + ldif_Entry *ldifentry_init(Slapi_Entry *); + int ldif_back_config( Slapi_PBlock *); + static char * ldif_read_one_record( FILE *); + int ldif_back_delete( Slapi_PBlock *); + int has_children(LDIF *, ldif_Entry *); + int ldif_back_init( Slapi_PBlock *); + + int ldif_back_search( Slapi_PBlock * ); + + int ldif_back_modrdn( Slapi_PBlock * ); + static int rdn2typeval(char *, char **, struct berval *); + void add_mod( LDAPMod ***, int, char *, struct berval ** ); + + int ldif_back_bind( Slapi_PBlock * ); + int ldif_back_unbind( Slapi_PBlock * ); + + int ldif_back_start( Slapi_PBlock * ); + void ldif_back_close( Slapi_PBlock * ); + void ldif_back_flush( Slapi_PBlock * ); + void ldif_free_db(LDIF *); + + int ldif_back_compare( Slapi_PBlock * ); + + char * get_monitordn(Slapi_PBlock * ); + int ldif_back_monitor_info( Slapi_PBlock *pb, LDIF *db); diff --git a/ldap/servers/slapd/back-ldif/bind.c b/ldap/servers/slapd/back-ldif/bind.c new file mode 100644 index 00000000..b95a589f --- /dev/null +++ b/ldap/servers/slapd/back-ldif/bind.c @@ -0,0 +1,108 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * File: bind.c + * + * Functions: + * + * ldif_back_bind() - ldap ldif back-end bind routine + * + */ + +#include "back-ldif.h" + +/* + * Function: ldif_back_bind + * + * Returns: returns 0|1 if good, -1 else. + * + * Description: performs an ldap bind. + */ +int +ldif_back_bind( Slapi_PBlock *pb ) +{ + char *dn; /*Storage for the dn*/ + int method; /*Storage for the bind method*/ + struct berval *cred; /*Storage for the bind credentials*/ + struct berval **bvals; + LDIF *db; /*The database*/ + ldif_Entry *e, *prev; /*Used for searching the db*/ + int rc, syntax; /*Storage for error return values*/ + Slapi_Attr *attr; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_bind\n", 0, 0, 0 ); + + prev = NULL; + + /*Get the parameters*/ + if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db ) < 0 || + slapi_pblock_get( pb, SLAPI_BIND_TARGET, &dn ) < 0 || + slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method ) < 0 || + slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &cred ) < 0){ + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + } + + /*Lock the database*/ + PR_Lock( db->ldif_lock ); + + + /*Find the entry that the person is attempting to bind as*/ + if ( (e = (ldif_Entry *)ldif_find_entry( pb, db, dn, &prev )) == NULL ) { + + /* Allow noauth binds */ + if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 ) { + rc = SLAPI_BIND_ANONYMOUS; + } else { + slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL ); + rc = SLAPI_BIND_FAIL; + } + + /*Unlock the database*/ + PR_Unlock( db->ldif_lock ); + + return( rc ); + } + + switch ( method ) { + case LDAP_AUTH_SIMPLE: + if ( cred->bv_len == 0 ) { + PR_Unlock( db->ldif_lock ); + return( SLAPI_BIND_ANONYMOUS ); + } + + if ( slapi_entry_attr_find( e->lde_e, "userpassword", &attr ) != 0 ) { + slapi_send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + return( SLAPI_BIND_FAIL ); + } + /* + * XXXmcs: slapi_attr_get_values() is deprecated and should be avoided + * See XXXmcs comments in ../attr.c for detailed information. + */ + slapi_attr_get_values( attr, &bvals ); + + if ( slapi_pw_find( bvals, cred ) != 0 ) { + slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + return( SLAPI_BIND_FAIL ); + } + break; + + default: + slapi_send_ldap_result( pb, LDAP_STRONG_AUTH_NOT_SUPPORTED, NULL, + "auth method not supported", 0, NULL ); + PR_Unlock( db->ldif_lock ); + return( SLAPI_BIND_FAIL ); + } + + PR_Unlock( db->ldif_lock ); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_bind\n", 0, 0, 0 ); + + /* success: front end will send result */ + return( SLAPI_BIND_SUCCESS ); +} diff --git a/ldap/servers/slapd/back-ldif/close.c b/ldap/servers/slapd/back-ldif/close.c new file mode 100644 index 00000000..34048eca --- /dev/null +++ b/ldap/servers/slapd/back-ldif/close.c @@ -0,0 +1,79 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * File: close.c + * + * Functions: + * + * ldif_back_close() - ldap ldif back-end close routine + * + */ + +#include "back-ldif.h" + +/* + * Function: ldif_free_db + * + * Returns: void + * + * Description: frees up the ldif database + */ +void +ldif_free_db(LDIF *db) +{ + ldif_Entry *cur; /*Used for walking down the list*/ + + /*If db is null, there is nothing to do*/ + if (db == NULL) { + return; + } + + /*Walk down the list, freeing up the ldif_entries*/ + for (cur = db->ldif_entries; cur != NULL; cur = cur->next){ + ldifentry_free(cur); + } + + /*Free the ldif_file string, and then the db itself*/ + free ((void *)db->ldif_file); + free((void *) db); +} + + + +/* + * Function: ldif_back_close + * + * Returns: void + * + * Description: closes the ldif backend, frees up the database + */ +void +ldif_back_close( Slapi_PBlock *pb ) +{ + LDIF *db; + + LDAPDebug( LDAP_DEBUG_TRACE, "ldbm backend syncing\n", 0, 0, 0 ); + slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db ); + ldif_free_db(db); + LDAPDebug( LDAP_DEBUG_TRACE, "ldbm backend done syncing\n", 0, 0, 0 ); +} + +/* + * Function: ldif_back_flush + * + * Returns: void + * + * Description: does nothing + */ +void +ldif_back_flush( Slapi_PBlock *pb ) +{ + LDAPDebug( LDAP_DEBUG_TRACE, "ldbm backend flushing\n", 0, 0, 0 ); + LDAPDebug( LDAP_DEBUG_TRACE, "ldbm backend done flushing\n", 0, 0, 0 ); + return; +} + + diff --git a/ldap/servers/slapd/back-ldif/compare.c b/ldap/servers/slapd/back-ldif/compare.c new file mode 100644 index 00000000..bb0c3754 --- /dev/null +++ b/ldap/servers/slapd/back-ldif/compare.c @@ -0,0 +1,82 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * File: compare.c + * + * Functions: + * + * ldif_back_compare() - ldap ldif back-end compare routine + * + */ + +#include "back-ldif.h" + +/* + * Function: ldif_back_compare + * + * Returns: -1, 0 or 1 + * + * Description: compares entries in the ldif backend + */ +int +ldif_back_compare( Slapi_PBlock *pb ) +{ + LDIF *db; /*The Database*/ + ldif_Entry *e, *prev; /*Used for searching the database*/ + char *dn, *type; /*The dn and the type*/ + struct berval *bval; + Slapi_Attr *attr; + int rc; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_compare\n", 0, 0, 0 ); + prev = NULL; + + if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db ) < 0 || + slapi_pblock_get( pb, SLAPI_COMPARE_TARGET, &dn ) < 0 || + slapi_pblock_get( pb, SLAPI_COMPARE_TYPE, &type ) < 0 || + slapi_pblock_get( pb, SLAPI_COMPARE_VALUE, &bval ) < 0){ + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + } + + /*Lock the database*/ + PR_Lock( db->ldif_lock ); + + + /*Find the entry for comparison*/ + if ( (e = (ldif_Entry*) ldif_find_entry( pb, db, dn, &prev )) == NULL ) { + slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + return( 1 ); + } + + /*Check the access*/ + rc= slapi_access_allowed( pb, e->lde_e, type, bval, SLAPI_ACL_COMPARE ); + if ( rc!=LDAP_SUCCESS ) { + slapi_send_ldap_result( pb, rc, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + return( 1 ); + } + + /*find the attribute*/ + if ( slapi_entry_attr_find( e->lde_e, type, &attr ) != 0 ) { + slapi_send_ldap_result( pb, LDAP_NO_SUCH_ATTRIBUTE, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + return( 1 ); + } + + if ( slapi_attr_value_find( attr, bval ) == 0 ) { + slapi_send_ldap_result( pb, LDAP_COMPARE_TRUE, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + return( 0 ); + } + + slapi_send_ldap_result( pb, LDAP_COMPARE_FALSE, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_compare\n", 0, 0, 0 ); + return( 0 ); +} + diff --git a/ldap/servers/slapd/back-ldif/config.c b/ldap/servers/slapd/back-ldif/config.c new file mode 100644 index 00000000..a62335a5 --- /dev/null +++ b/ldap/servers/slapd/back-ldif/config.c @@ -0,0 +1,203 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * File: config.c + * + * Functions: + * + * ldif_back_config() - Reads in and stores ldif file for ldif backend + * ldif_read_one_record() - Reads in one record from ldif file as a string + * + */ + +#include "back-ldif.h" +#define LDAPMOD_MAXLINE 4096 +#define safe_realloc( ptr, size ) ( ptr == NULL ? malloc( size ) : \ + realloc( ptr, size )) +static char *ldif_read_one_record(); + + +/* + * Function: ldif_back_config + * + * Returns: 0 if success, -1 if not + * + * Description: Reads the data in the ldif file specified in ldif.conf + * stores it in db + */ +int +ldif_back_config( Slapi_PBlock *pb ) +{ + LDIF *db; /*The ldif file will be read into this structure*/ + char *fname; /*Config file name*/ + int lineno, argc; /*Config file stuff*/ + char **argv; /*More config file stuff*/ + FILE *fp; /*Pointer to ldif file*/ + char *buf; /*Tmp storage for ldif entries*/ + int first; /*Boolean to determine if db is empty*/ + ldif_Entry *cur; /*For db manipulation*/ + ldif_Entry *new; /*For db manipulation*/ + Slapi_Entry *tmp; /*Used for initialization purposes*/ + + + LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_config\n", 0, 0, 0 ); + + /* + * Get the private_info structure you created in ldif_back_init(). + * Also get the config file name, current line number, and arguments + * from the current line, broken out into an argv. + */ + if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db ) < 0 || + slapi_pblock_get( pb, SLAPI_CONFIG_FILENAME, &fname ) < 0 || + slapi_pblock_get( pb, SLAPI_CONFIG_LINENO, &lineno ) < 0 || + slapi_pblock_get( pb, SLAPI_CONFIG_ARGC, &argc ) < 0 || + slapi_pblock_get( pb, SLAPI_CONFIG_ARGV, &argv ) < 0 ){ + LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: unable to get data from front end\n", 0, 0, 0); + return(-1); + } + + + /* + * Process the config info. For example, if the config file + * contains a line like this: + * + * file /path/to/ldif/file + * + * then argv[0] would be "file", and argv[1] would be the file + * name. + */ + + /*Check for the correct number of arguments*/ + if (argc != 2){ + LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: Unable to configure; invalid ldif input file specification line format (file: %s, line: %d)\n", + fname, lineno, 0); + return(-1); + } + + /*Check for the right format*/ + if (strcmp(argv[0], "file") != 0){ + LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: unable to configure; invalid parameter \"%s\" in config file (file: %s, line: %d)\n", + argv[0], fname, lineno ); + return(-1); + } + + /*Now we fopen the file and grab up the contents*/ + fp = fopen (argv[1], "r"); + if (fp == NULL){ + LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: unable to read ldif file %s\n", argv[1], 0, 0); + fp = fopen (argv[1], "w"); + if(fp == NULL){ + LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: unable to create ldif file %s\n", argv[1], 0, 0); + return -1; + } + } + + first = 1; + + /* Lock the database first, just to be safe*/ + PR_Lock( db->ldif_lock ); + + /*Save the filename, for modifications to the file later*/ + if ((db->ldif_file = strdup(argv[1])) == NULL){ + LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: out of memory\n", 0, 0, 0); + PR_Unlock( db->ldif_lock ); + fclose(fp); + return(-1); + } + + /* + * Loop through the entries in the file, and add them to the end + * of the linked list + */ + while ((buf = ldif_read_one_record(fp)) != NULL){ + + /*Create a new element for the linked list of entries*/ + tmp = (Slapi_Entry *) slapi_str2entry(buf, + SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF); + new = (ldif_Entry *) ldifentry_init(tmp); + if (new == NULL){ + LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: unable to read in ldif file; out of memory\n",0 ,0 ,0 ); + PR_Unlock( db->ldif_lock ); + fclose(fp); + return(-1); + } + + /* + * If this is the first entry we are adding, + * we have to make it the first element in the list + */ + if (first){ + db->ldif_entries = new; + first = 0; + } else{ + cur->next = new; + } + + /*Reset the pointer to the last element in the list*/ + cur = new; + + /*Increment the number of entries*/ + db->ldif_n++; + + /*Free the buffer*/ + free ((void *) buf ); + + } + + /*By now, the database should be read in*/ + PR_Unlock( db->ldif_lock ); + fclose(fp); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_config\n", 0, 0, 0 ); + return( 0 ); +} + + + +/* + * Function: ldif_read_one_record + * + * Returns: a long string representing an ldif record + * + * Description: Returns a huge string comprised of 1 ldif record + * read from fp. + * + */ +static char * +ldif_read_one_record( FILE *fp ) +{ + int len, gotnothing; + char *buff, line[ LDAPMOD_MAXLINE ]; + int lcur, lmax; + + lcur = lmax = 0; + buff = NULL; + gotnothing = 1; + + while ( fgets( line, sizeof(line), fp ) != NULL ) { + if ( (len = strlen( line )) < 2 ) { + if ( gotnothing ) { + continue; + } else { + break; + } + } + gotnothing = 0; + if ( lcur + len + 1 > lmax ) { + lmax = LDAPMOD_MAXLINE + * (( lcur + len + 1 ) / LDAPMOD_MAXLINE + 1 ); + if (( buff = (char *)safe_realloc( buff, lmax )) == NULL ) { + perror( "safe_realloc" ); + exit( LDAP_NO_MEMORY ); + } + } + strcpy( buff + lcur, line ); + lcur += len; + } + + return( buff ); +} + diff --git a/ldap/servers/slapd/back-ldif/delete.c b/ldap/servers/slapd/back-ldif/delete.c new file mode 100644 index 00000000..cf155ad4 --- /dev/null +++ b/ldap/servers/slapd/back-ldif/delete.c @@ -0,0 +1,136 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * File: delete.c + * + * Functions: + * + * ldif_back_delete() - ldap ldif back-end delete routine + * has_children() - determines if an entry has any children + * + */ + +#include "back-ldif.h" + +/* + * Function: ldif_back_delete + * + * Returns: returns 0 if good, -1 else. + * + * Description: For changetype: delete, this function deletes the entry + */ +int +ldif_back_delete( Slapi_PBlock *pb ) +{ + LDIF *db; /*The database*/ + ldif_Entry *bye, *prev; /*"bye" is the record to be deleted*/ + char *dn; /*Storage for the dn*/ + int rc; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_delete\n", 0, 0, 0 ); + + prev = NULL; + + /*Get the database and the dn to delete*/ + if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db ) < 0 || + slapi_pblock_get( pb, SLAPI_DELETE_TARGET, &dn ) < 0){ + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + } + + /*Lock the database*/ + PR_Lock( db->ldif_lock ); + + /* Find the entry we're about to delete*/ + bye = (ldif_Entry *) ldif_find_entry(pb, db, dn, &prev); + if (bye == NULL) { + slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL ); + LDAPDebug( LDAP_DEBUG_TRACE, "entry for delete does not exist\n", 0, 0, 0 ); + PR_Unlock( db->ldif_lock ); + return(-1); + } + + /*Make sure that we are trying to delete a leaf.*/ + if ( has_children( db, bye ) ) { + slapi_send_ldap_result( pb, LDAP_NOT_ALLOWED_ON_NONLEAF, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + return( -1 ); + } + + /*Check the access*/ + rc= slapi_access_allowed( pb, bye->lde_e, "entry", NULL, SLAPI_ACL_DELETE ); + if ( rc!=LDAP_SUCCESS) { + slapi_send_ldap_result( pb, rc, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + return( -1 ); + } + + /* Delete from disk and database */ + if ( update_db(pb, db, NULL, prev, LDIF_DB_DELETE) != 0){ + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + return(-1); + + } + + /*Success*/ + slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_delete\n", 0, 0, 0 ); + return( 0 ); +} + +/* + * Function: has_children + * + * Returns: returns 1 if the entry has kids, 0 else. + * + * Description: Determines if the entry has children + */ +int +has_children(LDIF *db, ldif_Entry *p) +{ + char *parentdn; /*Basically the dn of p (copied)*/ + char *childdn; /*Will be used to test if p has any children*/ + ldif_Entry *cur; /*Used to walk down the list*/ + int has_kid = 0; /*Flag to return*/ + + LDAPDebug( LDAP_DEBUG_TRACE, "=> has_children\n", 0, 0, 0); + + /*If there is no p or db, then there can be no children*/ + if (p == NULL || db == NULL){ + return(0); + } + + /*Get a copy of p's dn, and normalize it (squeeze any unneeded spaces out)*/ + parentdn = strdup( slapi_entry_get_dn(p->lde_e) ); + (void) slapi_dn_normalize( parentdn ); + + /*Walk down the list, seeing if each entry has p as a parent*/ + for (cur = db->ldif_entries; cur != NULL; cur = cur->next){ + childdn = strdup(slapi_entry_get_dn(cur->lde_e)); + (void) slapi_dn_normalize(childdn); + + /*Test to see if this childdn is a child of the parentdn*/ + if (slapi_dn_issuffix( childdn, parentdn ) && strlen(childdn) > strlen(parentdn)) + { + has_kid = 1; + free( (void *) childdn); + break; + } + free( (void *) childdn); + + } + + free( (void *) parentdn ); + + LDAPDebug( LDAP_DEBUG_TRACE, "<= has_children %d\n", has_kid, 0, 0); + return( has_kid ); +} + + + + diff --git a/ldap/servers/slapd/back-ldif/dllmain.c b/ldap/servers/slapd/back-ldif/dllmain.c new file mode 100644 index 00000000..69d0ceb5 --- /dev/null +++ b/ldap/servers/slapd/back-ldif/dllmain.c @@ -0,0 +1,132 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * Microsoft Windows specifics for LIBLDAP DLL + */ +#include "ldap.h" + + +#ifdef _WIN32 +/* Lifted from Q125688 + * How to Port a 16-bit DLL to a Win32 DLL + * on the MSVC 4.0 CD + */ +BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved) +{ + WSADATA wsadata; + + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + /* Code from LibMain inserted here. Return TRUE to keep the + DLL loaded or return FALSE to fail loading the DLL. + + You may have to modify the code in your original LibMain to + account for the fact that it may be called more than once. + You will get one DLL_PROCESS_ATTACH for each process that + loads the DLL. This is different from LibMain which gets + called only once when the DLL is loaded. The only time this + is critical is when you are using shared data sections. + If you are using shared data sections for statically + allocated data, you will need to be careful to initialize it + only once. Check your code carefully. + + Certain one-time initializations may now need to be done for + each process that attaches. You may also not need code from + your original LibMain because the operating system may now + be doing it for you. + */ + /* + * 16 bit code calls UnlockData() + * which is mapped to UnlockSegment in windows.h + * in 32 bit world UnlockData is not defined anywhere + * UnlockSegment is mapped to GlobalUnfix in winbase.h + * and the docs for both UnlockSegment and GlobalUnfix say + * ".. function is oboslete. Segments have no meaning + * in the 32-bit environment". So we do nothing here. + */ + + if( errno = WSAStartup(0x0101, &wsadata ) != 0 ) + return FALSE; + + break; + + case DLL_THREAD_ATTACH: + /* Called each time a thread is created in a process that has + already loaded (attached to) this DLL. Does not get called + for each thread that exists in the process before it loaded + the DLL. + + Do thread-specific initialization here. + */ + break; + + case DLL_THREAD_DETACH: + /* Same as above, but called when a thread in the process + exits. + + Do thread-specific cleanup here. + */ + break; + + case DLL_PROCESS_DETACH: + /* Code from _WEP inserted here. This code may (like the + LibMain) not be necessary. Check to make certain that the + operating system is not doing it for you. + */ + WSACleanup(); + + break; + } + /* The return value is only used for DLL_PROCESS_ATTACH; all other + conditions are ignored. */ + return TRUE; // successful DLL_PROCESS_ATTACH +} +#else +int CALLBACK +LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine ) +{ + /*UnlockData( 0 );*/ + return( 1 ); +} +#endif + +#ifdef LDAP_DEBUG +#ifndef _WIN32 +#include <stdarg.h> +#include <stdio.h> + +void LDAPDebug( int level, char* fmt, ... ) +{ + static char debugBuf[1024]; + + if (slapd_ldap_debug & level) + { + va_list ap; + va_start (ap, fmt); + _snprintf (debugBuf, sizeof(debugBuf), fmt, ap); + va_end (ap); + + OutputDebugString (debugBuf); + } +} +#endif +#endif + +#ifndef _WIN32 + +/* The 16-bit version of the RTL does not implement perror() */ + +#include <stdio.h> + +void perror( const char *msg ) +{ + char buf[128]; + wsprintf( buf, "%s: error %d\n", msg, WSAGetLastError()) ; + OutputDebugString( buf ); +} + +#endif diff --git a/ldap/servers/slapd/back-ldif/init.c b/ldap/servers/slapd/back-ldif/init.c new file mode 100644 index 00000000..8196d371 --- /dev/null +++ b/ldap/servers/slapd/back-ldif/init.c @@ -0,0 +1,114 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * File: init.c + * + * Functions: + * + * ldif_back_init() - ldap ldif back-end initialize routine + * + */ + +#include "back-ldif.h" + +static Slapi_PluginDesc pdesc = { "ldif-backend", "Netscape", PRODUCTTEXT, + "LDIF backend database plugin" }; + +#ifdef _WIN32 +int *module_ldap_debug = 0; + +void plugin_init_debug_level(int *level_ptr) +{ + module_ldap_debug = level_ptr; +} +#endif + +/* + * Function: ldif_back_init + * + * Returns: returns 0 if good, -1 else. + * + * Description: Allocates a database for filling by ldif_back_config + */ +int +ldif_back_init( Slapi_PBlock *pb ) +{ + LDIF *db; /*This will hold the ldif file in memory*/ + int rc; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_init\n", 0, 0, 0 ); + + /* + * Allocate and initialize db with everything we + * need to keep track of in this backend. In ldif_back_config(), + * we will fill in db with things like the name + * of the ldif file containing the database, and any other + * options we allow people to set through the config file. + */ + + /*Allocate memory for our database and check if success*/ + db = (LDIF *) malloc( sizeof(LDIF) ); + if (db == NULL) { + LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: unable to initialize; out of memory\n", 0, 0, 0); + return(-1); + } + + /*Fill with initial values, including the mutex*/ + db->ldif_n = 0; + db->ldif_entries = NULL; + db->ldif_tries = 0; + db->ldif_hits = 0; + db->ldif_file = NULL; + db->ldif_lock = PR_NewLock(); + if (&db->ldif_lock == NULL) { + LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: Lock creation failed\n", 0, 0, 0); + return(-1); + } + + + /* + * set SLAPI_PLUGIN_PRIVATE field in pb, so it's available + * later in ldif_back_config(), ldif_back_search(), etc. + */ + rc = slapi_pblock_set( pb, SLAPI_PLUGIN_PRIVATE, (void *) db ); + rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *) &pdesc ); + rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, + (void *) SLAPI_PLUGIN_VERSION_01 ); + rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_BIND_FN, + (void *) ldif_back_bind ); + rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_UNBIND_FN, + (void *) ldif_back_unbind ); + rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_SEARCH_FN, + (void *) ldif_back_search ); + rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_COMPARE_FN, + (void *) ldif_back_compare ); + rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_MODIFY_FN, + (void *) ldif_back_modify ); + rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_MODRDN_FN, + (void *) ldif_back_modrdn ); + rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_ADD_FN, + (void *) ldif_back_add ); + rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_DELETE_FN, + (void *) ldif_back_delete ); + rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_CONFIG_FN, + (void *) ldif_back_config ); + rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN, + (void *) ldif_back_close ); + rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_FLUSH_FN, + (void *) ldif_back_flush ); + rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN, + (void *) ldif_back_start ); + if (rc != 0) { + LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: unable to pass database information to front end\n",0 ,0 ,0); + return(-1); + } + + LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_init\n", 0, 0, 0 ); + + return( 0 ); +} + + diff --git a/ldap/servers/slapd/back-ldif/libback-ldif.def b/ldap/servers/slapd/back-ldif/libback-ldif.def new file mode 100644 index 00000000..f4724f97 --- /dev/null +++ b/ldap/servers/slapd/back-ldif/libback-ldif.def @@ -0,0 +1,12 @@ +; BEGIN COPYRIGHT BLOCK +; Copyright 2001 Sun Microsystems, Inc. +; Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +; All rights reserved. +; END COPYRIGHT BLOCK +; +DESCRIPTION 'Directory Server LDIF Backend Plugin' +EXPORTS + ldif_back_init @2 + plugin_init_debug_level @3 + + diff --git a/ldap/servers/slapd/back-ldif/modify.c b/ldap/servers/slapd/back-ldif/modify.c new file mode 100644 index 00000000..53f0bb2e --- /dev/null +++ b/ldap/servers/slapd/back-ldif/modify.c @@ -0,0 +1,557 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * File: modify.c + * + * Functions: + * + * ldif_back_modify() - ldif backend modify function + * update_db() - updates memory and disk db to reflect changes + * db2disk() - writes out ldif database to disk + * ldifentry_free() - frees an ldif_Entry + * ldifentry_dup() - copies an ldif_Entry + * ldif_find_entry() - searches an ldif DB for a particular dn + * apply_mods() - applies the modifications to an Entry + * + */ + +#include "back-ldif.h" + +/*Prototypes*/ +void ldifentry_free(ldif_Entry *); +ldif_Entry * ldifentry_dup(ldif_Entry *); +int apply_mods( Slapi_Entry *, LDAPMod ** ); +ldif_Entry * ldif_find_entry(Slapi_PBlock *, LDIF *, char *, ldif_Entry **); +int db2disk(Slapi_PBlock *, LDIF *); +int update_db(Slapi_PBlock *, LDIF *, ldif_Entry *, ldif_Entry *, int ); + +/* + * Function: ldif_back_modify + * + * Returns: returns 0 if good, -1 else. + * + * Description: For changetype: modify, this makes the changes + */ +int +ldif_back_modify( Slapi_PBlock *pb ) +{ + LDIF *db; /*The ldif file is stored here*/ + ldif_Entry *entry, *entry2,*prev; /*For db manipulation*/ + int err; /*House keeping stuff*/ + LDAPMod **mods; /*Used to apply the modifications*/ + char *dn; /*Storage for the dn*/ + char *errbuf = NULL; /* To get error back */ + + LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_modify\n", 0, 0, 0 ); + prev = NULL; + + /*Get the database, the dn and the mods*/ + if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db ) < 0 || + slapi_pblock_get( pb, SLAPI_MODIFY_TARGET, &dn ) < 0 || + slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods ) < 0){ + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + } + /*Lock the database*/ + PR_Lock( db->ldif_lock ); + + /* + * Find the entry we are about to modify. + * prev will point to the previous element in the list, + * NULL if there is no previous element. + */ + if ( (entry = (ldif_Entry *)ldif_find_entry( pb, db, dn, &prev)) == NULL ) { + slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + return( -1 ); + } + + /*Check acl, note that entry is not an Entry, but a ldif_Entry*/ + if ( (err = slapi_acl_check_mods( pb, entry->lde_e, mods, &errbuf )) != LDAP_SUCCESS ) { + slapi_send_ldap_result( pb, err, NULL, errbuf, 0, NULL ); + if (errbuf) free (errbuf); + PR_Unlock( db->ldif_lock ); + goto error_return; + } + + /* Create a copy of the entry and apply the changes to it */ + if ( (entry2 = (ldif_Entry *) ldifentry_dup( entry )) == NULL ) { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + goto error_return; + } + + /*Actually apply the modifications*/ + if ( (err = apply_mods( entry2->lde_e, mods )) != 0 ) { + slapi_send_ldap_result( pb, err, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + goto error_return; + } + + /* Check for abandon */ + if ( slapi_op_abandoned( pb ) ) { + PR_Unlock( db->ldif_lock ); + goto error_return; + } + + /* Check that the entry still obeys the schema */ + if ( slapi_entry_schema_check( pb, entry2->lde_e ) != 0 ) { + slapi_send_ldap_result( pb, LDAP_OBJECT_CLASS_VIOLATION, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + goto error_return; + } + + /* Check for abandon again */ + if ( slapi_op_abandoned( pb ) ) { + PR_Unlock( db->ldif_lock ); + goto error_return; + } + + /* Change the entry itself both on disk and in the cache */ + if ( update_db(pb, db, entry2, prev, LDIF_DB_REPLACE) != 0) { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + goto error_return; + } + + slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_modify\n", 0, 0, 0 ); + return( 0 ); + + error_return:; + if ( entry2 != NULL ) { + ldifentry_free( entry2 ); + } + + return( -1 ); +} + +/* + * Function: update_db + * + * Returns: returns 0 if good, -1 else. + * + * Description: Will update the database in memory, and on disk + * if prev == NULL, then the element to be deleted/replaced + * is the first in the list. + * mode = LDIF_DB_ADD | LDIF_DB_REPLACE | LDIF_DB_DELETE + * The database should be locked when this function is called. + * Note that on replaces and deletes, the old ldif_Entry's + * are freed. + */ +int +update_db(Slapi_PBlock *pb, LDIF *db, ldif_Entry *new, ldif_Entry *prev, int mode) +{ + ldif_Entry *tmp; /*Used to free the removed/replaced entries*/ + char *buf; /*Used to convert entries to strings for output to file*/ + FILE *fp; /*File ptr to the ldif file*/ + int len; /*Used by slapi_entry2str*/ + int db_updated=0; /*Flag to designate if db in memory has been updated*/ + + /*Make sure that the database is not null. Everything else can be, though*/ + if (db == NULL){ + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + } + + /* + * If we are adding an entry, then prev should be pointing + * to the last element in the list, or null if the list is empty, + * and new should not be null. + */ + if (mode == LDIF_DB_ADD) { + + /*Make sure there is something to add*/ + if ( new == NULL ) { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + } + + /*If prev is null, then there had better be no entries in the list*/ + if (prev == NULL){ + if( db->ldif_entries != NULL) { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + } + /*There are no elements, so let's add the new one*/ + db->ldif_entries = new; + db->ldif_n++; + + /*Set a flag*/ + db_updated = 1; + + } + /* + * Last error case to test for is if prev is not null, and prev->next + * points to something. This means that we are not at the end of the list + */ + if (prev != NULL) { + if (prev->next != NULL) { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + } + + /*We're at the end of the list, so tack the new entry onto the end*/ + prev->next = new; + db->ldif_n++; + + db_updated = 1; + + } + + /*If the database has been updated in memory, update the disk*/ + if (db_updated && db->ldif_file!=NULL) { + + /*Update the disk by appending to the ldif file*/ + fp = fopen(db->ldif_file, "a"); + if (fp == NULL) { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + /*This is s pretty serious problem, so we exit*/ + exit(-1); + } + + /*Convert the entry to ldif format*/ + buf = slapi_entry2str(new->lde_e, &len); + fprintf(fp, "%s\n", buf); + free ( (void *) buf); + fclose(fp); + return(0); + } else { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + fclose(fp); + return(-1); + + } + + } else if (mode == LDIF_DB_DELETE){ + + /*We're not deleting the first entry in the list*/ + if (prev != NULL){ + /*Make sure there is something to delete*/ + if (prev->next == NULL) { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + } + tmp = prev->next; + prev->next = tmp->next; + db->ldif_n--; + ldifentry_free(tmp); + + db_updated = 1; + + } else { /*We are deleting the first entry in the list*/ + + /*Make sure there is something to delete*/ + if (db->ldif_entries == NULL) { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + } + + tmp = db->ldif_entries; + db->ldif_entries = tmp->next; + db->ldif_n--; + + /*Free the entry, and set the flag*/ + ldifentry_free(tmp); + db_updated = 1; + } + + /* + * Update the disk by rewriting entire ldif file + * I know, I know, but simplicity is the key here. + */ + if (db_updated) { + return(db2disk(pb, db)); + } else { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + + } + + } else if (mode == LDIF_DB_REPLACE) { + + /*Make sure there is something to replace with*/ + if ( new == NULL ) { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + } + + + /*We're not replacing the first element in the list*/ + if (prev != NULL){ + + /*Make sure there is something to replace*/ + if (prev->next == NULL) { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + } + + /*Splice out the old entry, and put in the new*/ + tmp = prev->next; + prev->next = new; + new->next = tmp->next; + + /*Free it*/ + ldifentry_free(tmp); + db_updated = 1; + } else { /*We are replacing the first entry in the list*/ + + /*Make sure there is something to replace*/ + if (db->ldif_entries == NULL) { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + } + + /*Splice out the old entry, and put in the new*/ + tmp = db->ldif_entries; + db->ldif_entries = new; + new->next = tmp->next; + + /*Free it*/ + ldifentry_free(tmp); + db_updated = 1; + } + + /*Update the disk by rewriting entire ldif file*/ + if (db_updated) { + return(db2disk(pb, db)); + } else { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + } + + } +} + +/* + * Function: db2disk + * + * Returns: returns 0 if good, exits else + * + * Description: Takes an ldif database, db, and writes it out to disk + * if it can't open the file, there's trouble, so we exit + * because this function is usually called after the db + * in memory has been updated. + * + */ +int +db2disk(Slapi_PBlock *pb, LDIF *db) +{ + ldif_Entry *cur; /*Used for walking down the list*/ + char *buf; /*temp storage for Entry->ldif converter*/ + FILE *fp; /*File pointer to ldif target file*/ + int len; /*length returned by slapi_entry2str*/ + + /*Open the file*/ + fp = fopen(db->ldif_file, "w"); + if (fp == NULL) { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + /*This is s pretty serious problem, so we exit*/ + exit(-1); + } + + /* + * Walk down the list, converting each entry to a string, + * writing the string out to fp + */ + for (cur = db->ldif_entries; cur != NULL; cur = cur->next){ + buf = slapi_entry2str(cur->lde_e, &len); + fprintf(fp, "%s\n",buf); + free ( (void *) buf); + } + + fclose(fp); + return(0); + +} + + +/* + * Function: ldifentry_free + * + * Returns: void + * + * Description: Frees an ldif_Entry + */ +void +ldifentry_free(ldif_Entry *e) +{ + + /*Make sure that there is actually something to free*/ + if (e == NULL){ + return; + } + + /*Free the entry*/ + slapi_entry_free(e->lde_e); + + /*Free the entire thing*/ + free ((void *) e); +} + +/* + * Function: ldifentry_dup + * + * Returns: a pointer to the new ldif_entry, or NULL + * + * Description: Copies and returns a pointer to a new + * ldif_Entry whose contents are a copy of e's contents + * Note: uses malloc + */ +ldif_Entry * +ldifentry_dup(ldif_Entry *e) +{ + ldif_Entry *new; + + /*Let's make sure that e is not null*/ + if (e == NULL){ + return(NULL); + } + + /*Allocate a new ldif_entry, and return it if it is null*/ + new = (ldif_Entry *) malloc( (sizeof(ldif_Entry))); + if (new == NULL) { + return(new); + } + + /*Copy the Entry in e*/ + new->lde_e = slapi_entry_dup(e->lde_e); + new->next = NULL; + + return(new); + + +} + +/* + * Function: ldif_find_entry + * + * Returns: A pointer to the matched ldif_Entry, or Null + * + * Description: Goes down the list of entries in db to find the entry + * matching dn. Returns a pointer to the entry, + * and sets prev to point to the entry before the match. + * If there is no match, prev points to the last + * entry in the list, and null is returned. + * If the first element matches, prev points to NULL + */ +ldif_Entry * +ldif_find_entry(Slapi_PBlock *pb, LDIF *db, char *dn, ldif_Entry **prev) +{ + ldif_Entry *cur; /*Used for walking down the list*/ + char *finddn, *targetdn; /*Copies of dns for searching */ + int found_it = 0; /*A flag to denote a successful search*/ + + /*Set cur to the start of the list*/ + cur =db->ldif_entries; + + /*Increase the number of accesses*/ + db->ldif_tries++; + + /*Make a copy of the target dn, and normalize it*/ + targetdn = strdup(dn); + (void) slapi_dn_normalize(targetdn); + + + /*Go down the list until we find the entry*/ + while(cur != NULL) { + finddn = strdup(slapi_entry_get_dn(cur->lde_e)); + (void) slapi_dn_normalize(finddn); + + + /*Test to see if we got the entry matching the dn*/ + if (strcasecmp(targetdn, finddn) == 0) + { + found_it = 1; + free ((void *)finddn); + db->ldif_hits++; + break; + } + + /*Udpate the pointers*/ + *prev = cur; + cur = cur->next; + free ((void *)finddn); + + } + + free ((void *)targetdn); + + + /* + * If we didn't find a matching entry, we should + * return, and let the caller handle this (possible) error + */ + if (!found_it){ + return(NULL); + } + + /* + * If the first entry matches, we have to set prev to null, + * so the caller knows. + */ + if (*prev == cur){ + *prev = NULL; + } + + return( cur ); +} + +/* + * Function: apply_mods + * + * Returns: LDAP_SUCCESS if success + * + * Description: Applies the modifications specified in mods to e. + */ +int +apply_mods( Slapi_Entry *e, LDAPMod **mods ) +{ + int err, i, j; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> apply_mods\n", 0, 0, 0 ); + + err = LDAP_SUCCESS; + for ( j = 0; mods[j] != NULL; j++ ) { + switch ( mods[j]->mod_op & ~LDAP_MOD_BVALUES ) { + case LDAP_MOD_ADD: + LDAPDebug( LDAP_DEBUG_ARGS, " add: %s\n", + mods[j]->mod_type, 0, 0 ); + err = slapi_entry_add_values( e, mods[j]->mod_type, + mods[j]->mod_bvalues ); + break; + + case LDAP_MOD_DELETE: + LDAPDebug( LDAP_DEBUG_ARGS, " delete: %s\n", + mods[j]->mod_type, 0, 0 ); + err = slapi_entry_delete_values( e, mods[j]->mod_type, + mods[j]->mod_bvalues ); + break; + + case LDAP_MOD_REPLACE: + LDAPDebug( LDAP_DEBUG_ARGS, " replace: %s\n", + mods[j]->mod_type, 0, 0 ); + err = entry_replace_values( e, mods[j]->mod_type, + mods[j]->mod_bvalues ); + break; + } + for ( i = 0; mods[j]->mod_bvalues != NULL && + mods[j]->mod_bvalues[i] != NULL; i++ ) { + LDAPDebug( LDAP_DEBUG_ARGS, " %s: %s\n", + mods[j]->mod_type, mods[j]->mod_bvalues[i]->bv_val, + 0 ); + } + LDAPDebug( LDAP_DEBUG_ARGS, " -\n", 0, 0, 0 ); + + if ( err != LDAP_SUCCESS ) { + break; + } + } + + LDAPDebug( LDAP_DEBUG_TRACE, "<= apply_mods %d\n", err, 0, 0 ); + return( err ); +} diff --git a/ldap/servers/slapd/back-ldif/modrdn.c b/ldap/servers/slapd/back-ldif/modrdn.c new file mode 100644 index 00000000..d2dfcdb8 --- /dev/null +++ b/ldap/servers/slapd/back-ldif/modrdn.c @@ -0,0 +1,282 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * File: modrdn.c + * + * Functions: + * + * ldif_back_modrdn() - ldap ldif back-end modrdn routine + * rdn2typval() - rdn to typval converter + * ldif_add_mod() - Adds a modification to be performed. + * + */ + +#include "back-ldif.h" +int rdn2typval(char *, char **, struct berval *); +void ldif_add_mod( LDAPMod ***, int, char *, struct berval ** ); + +/* + * Function: ldif_back_modrdn + * + * Returns: returns 0 if good, -1 else. + * + * Description: For changetype: modrdn, this modifies the rdn of the entry + */ +int +ldif_back_modrdn( Slapi_PBlock *pb ) +{ + LDIF *db; /*ldif backend database*/ + ldif_Entry *prev, *tprev, *entry, *entry2, *test; + char *pdn, *newdn; /*Used for dn manipulation*/ + char *dn, *newrdn, *type; /*Used for dn manipulation*/ + int i; /*A counter*/ + char **rdns, **dns; /*Used for dn manipulation*/ + int deleteoldrdn; /*Flag from user to delete old rdn*/ + struct berval bv; + struct berval *bvps[2]; + LDAPMod **mods; /*Holds the list of modifications*/ + int rc; + + LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_modrdn\n", 0, 0, 0 ); + + prev = NULL; + + /*Get the information from the front end, including the database*/ + if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db )< 0 || + slapi_pblock_get( pb, SLAPI_MODRDN_TARGET, &dn ) < 0 || + slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn ) < 0 || + slapi_pblock_get( pb, SLAPI_MODRDN_DELOLDRDN, &deleteoldrdn ) <0){ + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + + } + + /*Lock the database*/ + PR_Lock( db->ldif_lock ); + + /* + * Find the entry we are about to modify + * prev will point to the previous element in the list, + * NULL if there is no previous element + */ + if ( (entry = (ldif_Entry *)ldif_find_entry( pb, db, dn, &prev)) == NULL ) { + slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + return( -1 ); + } + + /*Make sure that we are trying to modify the rdn of a leaf.*/ + if ( has_children( db, entry ) ) { + slapi_send_ldap_result( pb, LDAP_NOT_ALLOWED_ON_NONLEAF, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + return( -1 ); + } + + + /* Create a copy of the entry and apply the changes to it */ + if ( (entry2 = (ldif_Entry *)ldifentry_dup( entry )) == NULL ) { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + PR_Unlock( db->ldif_lock ); + return( -1 ); + } + + /*Check the access*/ + rc= slapi_access_allowed( pb, entry2->lde_e, NULL, NULL, SLAPI_ACL_WRITE ); + if ( rc!=LDAP_SUCCESS ) { + slapi_send_ldap_result( pb, rc, NULL, NULL, 0, NULL ); + ldifentry_free( entry2 ); + PR_Unlock( db->ldif_lock ); + return( -1 ); + } + + /* Construct the new dn */ + if ( (pdn = slapi_dn_beparent( pb, dn )) != NULL ) { + + /* parent + rdn + separator(s) + null */ + newdn = (char *) malloc( strlen( pdn ) + strlen( newrdn ) + 3 ); + if (newdn == NULL){ + LDAPDebug( LDAP_DEBUG_ANY,"malloc failed", 0, 0, 0 ); + exit(1); + } + + strcpy( newdn, newrdn ); + strcat( newdn, ", " ); + strcat( newdn, pdn ); + } else { + newdn = strdup( newrdn ); + } + free( pdn ); + + /*Normalize the newdn, that is, squeeze out all unnecessary spaces*/ + (void) slapi_dn_normalize( newdn ); + + + /* Add the new dn to our working copy of the entry */ + slapi_entry_set_dn( entry2->lde_e, newdn ); + + + /* See if an entry with the new name already exists */ + if ( (test = (ldif_Entry *)ldif_find_entry( pb, db, newdn, &tprev )) != NULL ) { + slapi_send_ldap_result( pb, LDAP_ALREADY_EXISTS, NULL, NULL, 0, NULL ); + + goto error_return; + } + + + /* + * Delete old rdn values from the entry if deleteoldrdn is set. + * Add new rdn values to the entry. + */ + mods = NULL; + bvps[0] = &bv; + bvps[1] = NULL; + if ( (dns = ldap_explode_dn( dn, 0 )) != NULL ) { + if ( (rdns = ldap_explode_rdn( dns[0], 0 )) != NULL ) { + for ( i = 0; rdns[i] != NULL; i++ ) { + + /* Delete from entry attributes */ + if ( deleteoldrdn && rdn2typval( rdns[i], &type, &bv ) == 0 ) { + ldif_add_mod( &mods, LDAP_MOD_DELETE, type, bvps ); + } + } + ldap_value_free( rdns ); + } + ldap_value_free( dns ); + } + if ( dns == NULL || rdns == NULL ) { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + goto error_return; + } + /* Add new rdn values to the entry */ + if ( (rdns = ldap_explode_rdn( newrdn, 0 )) != NULL ) { + for ( i = 0; rdns[i] != NULL; i++ ) { + /* Add to entry */ + if ( rdn2typval( rdns[i], &type, &bv ) == 0 ) { + ldif_add_mod( &mods, LDAP_MOD_ADD, type, bvps ); + } + } + ldap_value_free( rdns ); + } else { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + goto error_return; + } + bv.bv_val = newdn; + bv.bv_len = strlen( newdn ); + ldif_add_mod( &mods, LDAP_MOD_REPLACE, "entrydn", bvps ); + + /* Check for abandon */ + if ( slapi_op_abandoned( pb ) ) { + goto error_return; + } + + /* Apply the mods we built above to the copy of the entry */ + if ( apply_mods( entry2->lde_e, mods ) != 0 ) { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + + goto error_return; + } + + /* Update the database and the disk */ + if ( update_db(pb, db, entry2, prev, LDIF_DB_REPLACE) != 0) { + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + + goto error_return; + } + + /*Unlock the database, and tell the user the good news*/ + PR_Unlock( db->ldif_lock ); + slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL ); + LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_modrdn\n", 0, 0, 0 ); + return( 0 ); + +error_return:; + + /* Result already sent above - just free stuff */ + PR_Unlock( db->ldif_lock ); + ldifentry_free( entry2 ); + + return( -1 ); +} + +/* + * Function: rdn2typval + * + * Returns: returns 0 if good, -1 else. + * + * Description: converts an rdn to a typeval + */ +int +rdn2typval(char *rdn, char **type, struct berval *bv) +{ + char *s; + + if ( (s = strchr( rdn, '=' )) == NULL ) { + return( -1 ); + } + *s++ = '\0'; + + *type = rdn; + bv->bv_val = s; + bv->bv_len = strlen( s ); + + return( 0 ); +} + +/* + * Function: ldif_add_mod + * + * Returns: void + * + * Description: Adds a modification (add, delete, etc) to the list + * of modifications that will eventually be made to some entry + */ +void +ldif_add_mod( LDAPMod ***modlist, int modtype, char *type, struct berval **bvps ) +{ + int i; + + for ( i = 0; modlist[i] != NULL; i++ ) { + ; /* NULL */ + } + + *modlist = (LDAPMod **) realloc( (char *) *modlist, + (i + 2) * sizeof(LDAPMod *) ); + + if (*modlist == NULL){ + LDAPDebug( LDAP_DEBUG_ANY, "realloc failed", 0, 0, 0 ); + exit(1); + } + (*modlist)[i] = (LDAPMod *) malloc( sizeof(LDAPMod) ); + + if ((*modlist)[i] == NULL){ + LDAPDebug( LDAP_DEBUG_ANY,"malloc failed", 0, 0, 0 ); + exit(1); + } + + (*modlist)[i]->mod_type = (char *) strdup( type ); + if ((*modlist)[i]->mod_type == NULL){ + LDAPDebug( LDAP_DEBUG_ANY,"strdup failed", 0, 0, 0 ); + exit(1); + } + + + (*modlist)[i]->mod_op = modtype; + (*modlist)[i]->mod_bvalues = (struct berval **) malloc(2*sizeof(struct berval *)); + if ((*modlist)[i]->mod_bvalues == NULL){ + LDAPDebug( LDAP_DEBUG_ANY,"malloc failed",0, 0, 0 ); + exit(1); + } + (*modlist)[i]->mod_bvalues[0] = ber_bvdup( bvps[0] ); + (*modlist)[i]->mod_bvalues[1] = NULL; + (*modlist)[i+1] = NULL; +} + + + + + + + diff --git a/ldap/servers/slapd/back-ldif/monitor.c b/ldap/servers/slapd/back-ldif/monitor.c new file mode 100644 index 00000000..b4b721b0 --- /dev/null +++ b/ldap/servers/slapd/back-ldif/monitor.c @@ -0,0 +1,124 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * File: monitor.c + * + * Functions: + * + * ldif_back_monitor_info() - ldap ldif back-end initialize routine + * + * get_monitordn() - gets the monitor dn for this backend + * + */ + +#include "back-ldif.h" + +extern char Versionstr[]; + + +/* + * Function: ldif_back_monitor_info + * + * Returns: returns 1 + * + * Description: This function wraps up backend specific monitor information + * and returns it to the client as an entry. This function + * is usually called by ldif_back_search upon receipt of + * the monitor dn for this backend. + */ +int +ldif_back_monitor_info( Slapi_PBlock *pb, LDIF *db) +{ + Slapi_Entry *e; /*Entry*/ + char buf[BUFSIZ]; /*Buffer for getting the attrs*/ + struct berval val; /*More attribute storage*/ + struct berval *vals[2]; /*Even more*/ + char *type; /*Database name (type) */ + + vals[0] = &val; + vals[1] = NULL; + + /*Alloc the entry and set the monitordn*/ + e = slapi_entry_alloc(); + slapi_entry_set_dn(e, (char *) get_monitordn(pb)); + + /* Get the database name (be_type) */ + slapi_pblock_get( pb, SLAPI_BE_TYPE, &type); + sprintf( buf, "%s", type ); + val.bv_val = buf; + val.bv_len = strlen( buf ); + slapi_entry_attr_merge( e, "database", vals ); + + /*Lock the database*/ + PR_Lock( db->ldif_lock ); + + /*Get the number of database hits */ + sprintf( buf, "%ld", db->ldif_hits); + val.bv_val = buf; + val.bv_len = strlen( buf ); + slapi_entry_attr_merge( e, "entrycachehits", vals ); + + /*Get the number of database tries */ + sprintf( buf, "%ld", db->ldif_tries); + val.bv_val = buf; + val.bv_len = strlen( buf ); + slapi_entry_attr_merge( e, "entrycachetries", vals ); + + /*Get the current size of the entrycache (db) */ + sprintf( buf, "%ld", db->ldif_n); + val.bv_val = buf; + val.bv_len = strlen( buf ); + slapi_entry_attr_merge( e, "currententrycachesize", vals ); + + + /* + * Get the maximum size of the entrycache (db) + * in this database, there is no max, so return the current size + */ + val.bv_val = buf; + val.bv_len = strlen( buf ); + slapi_entry_attr_merge( e, "maxentrycachesize", vals ); + + /* Release the lock*/ + PR_Unlock( db->ldif_lock ); + + /*Send the results back to the client*/ + slapi_send_ldap_search_entry( pb, e, NULL, NULL, 0 ); + slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 1, NULL ); + + slapi_entry_free( e ); + + return(1); + + +} + + +/* + * Function: get_monitordn + * + * Returns: returns ptr to string if success, NULL else + * + * Description: get_monitordn takes a pblock and extracts the + * monitor dn of this backend. The monitordn is a special + * signal to the backend to return backend specific monitor + * information (usually called by back_ldif_search()). + */ +char * +get_monitordn(Slapi_PBlock *pb ) +{ + char *mdn; + + slapi_pblock_get( pb, SLAPI_BE_MONITORDN, &mdn ); + + if (mdn == NULL) { + return(NULL); + + } + + return(strdup(mdn)); + +} diff --git a/ldap/servers/slapd/back-ldif/search.c b/ldap/servers/slapd/back-ldif/search.c new file mode 100644 index 00000000..1f9adbfb --- /dev/null +++ b/ldap/servers/slapd/back-ldif/search.c @@ -0,0 +1,197 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * File: search.c + * + * Functions: + * + * ldif_back_search() - ldif backend search function + * + */ + +#include "back-ldif.h" + +/* + * Function: ldif_back_search + * + * Returns: returns 0 if good, -1 else. + * + * Description: Searches the database for entries satisfying the + * user's criteria + */ +int +ldif_back_search( Slapi_PBlock *pb ) +{ + LDIF *db; /*The database*/ + char *base; /*Base of the search*/ + int scope; /*Scope of the search*/ + int deref; /*Should we dereference aliases?*/ + int slimit; /*Size limit of the search*/ + int tlimit; /*Time limit of the search*/ + Slapi_Filter *filter; /*The filter*/ + time_t dummy=0; /*Used for time()*/ + char **attrs; /*Attributes*/ + int attrsonly; /*Should we just return the attributes found?*/ + time_t optime; /*Time the operation started*/ + int nentries; /*Number of entries found thus far*/ + ldif_Entry *cur; /*Used for traversing the list of entries*/ + int hitflag=0; /*Used to test if we found the entry in the db*/ + char *freeme; /*Tmp storage for monitordn*/ + time_t currtime; /*The current time*/ + + LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_search\n", 0, 0, 0 ); + + /* + * Get private information created in the init routine. + * Also get the parameters of the search operation. These come + * more or less directly from the client. + */ + if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db ) < 0 || + slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &base ) < 0 || + slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope ) < 0 || + slapi_pblock_get( pb, SLAPI_SEARCH_DEREF, &deref ) < 0 || + slapi_pblock_get( pb, SLAPI_SEARCH_SIZELIMIT, &slimit ) < 0 || + slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &tlimit ) < 0 || + slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter ) < 0 || + slapi_pblock_get( pb, SLAPI_SEARCH_ATTRS, &attrs ) < 0 || + slapi_pblock_get( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly ) <0 || + slapi_pblock_get( pb, SLAPI_OPINITIATED_TIME, &optime ) < 0){ + slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); + return(-1); + } + + + /* + * If we get a search request for the backend monitor dn, + * call ldif_back_monitor_info(), which packages up the + * backend database analysis info and sends it back to the + * client + */ + if ( scope == LDAP_SCOPE_BASE ) { + + /*Get the backend's monitor dn*/ + freeme = (char *) get_monitordn(pb); + + if (freeme != NULL){ + + /* + * Compare the monitor dn with the base, + * if they match, call monitor_info, which + * will return all the relevant info to the client + */ + if ( strcasecmp( base, freeme) == 0 ) { + ldif_back_monitor_info( pb, db ); + free ((void *) freeme); + return(-1); + } + free ((void *) freeme); + } + } + + + /* + * First we lock the whole database (clumsy, inefficient and + * inelegant, but simple) + */ + PR_Lock( db->ldif_lock ); + + /*Increase the number of accesses*/ + db->ldif_tries++; + + /* + * Look through each entry in the ldif file and see if it matches + * the filter and scope of the search. Do this by calling the + * slapi_filter_test() routine. + */ + nentries = 0; + for (cur=db->ldif_entries; cur != NULL; cur = cur->next ) { + + /*Make sure we're not exceeding our time limit...*/ + currtime = time(&dummy); + if ((tlimit > 0) && ((currtime - optime) > tlimit)){ + slapi_send_ldap_result( pb, LDAP_TIMELIMIT_EXCEEDED, NULL, NULL, nentries, NULL); + + /*We "hit" the cache*/ + if (hitflag) + { + db->ldif_hits++; + } + + PR_Unlock( db->ldif_lock ); + return(-1); + } + + /*...or that we haven't been abandoned*/ + if ( slapi_op_abandoned( pb ) ) { + + /*We "hit" the cache*/ + if (hitflag) + { + db->ldif_hits++; + } + + PR_Unlock( db->ldif_lock ); + return( -1 ); + } + + /*Test for exceedence of size limit*/ + if ((slimit > -1) && (nentries >= slimit)){ + slapi_send_ldap_result( pb, LDAP_SIZELIMIT_EXCEEDED, NULL, NULL, nentries, NULL); + + /*We hit the "cache"*/ + if (hitflag) + { + db->ldif_hits++; + } + PR_Unlock( db->ldif_lock ); + return(-1); + } + + + + /*Test if this entry matches the filter*/ + if ( slapi_vattr_filter_test( pb, cur->lde_e, filter, 1 /* verify access */ ) == 0 ) { + + /* Entry matches - send it */ + hitflag = 1; + + switch ( slapi_send_ldap_search_entry( pb, cur->lde_e, NULL, attrs, + attrsonly ) ) { + case 0: /* Entry sent ok */ + nentries++; + break; + case 1: /* Entry not sent - because of acl, etc. */ + break; + case -1:/* Connection closed */ + /* Clean up and return */ + + /*We "hit" the cache*/ + if (hitflag) + { + db->ldif_hits++; + } + PR_Unlock( db->ldif_lock ); + return( -1 ); + } + + + } + } + + /*If we succeeded, we should update the ldif_hits entry of db*/ + if (hitflag) + { + db->ldif_hits++; + } + + + /* Search is done, send LDAP_SUCCESS */ + slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, nentries, NULL ); + PR_Unlock( db->ldif_lock ); + LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_search\n", 0, 0, 0 ); + return( -1 ); + +} diff --git a/ldap/servers/slapd/back-ldif/start.c b/ldap/servers/slapd/back-ldif/start.c new file mode 100644 index 00000000..4e22cb08 --- /dev/null +++ b/ldap/servers/slapd/back-ldif/start.c @@ -0,0 +1,31 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * File: start.c + * + * Functions: + * + * ldif_back_start() - ldap ldif back-end start routine + * + */ +#include "back-ldif.h" + +/* + * Function: ldif_back_start + * + * Returns: returns 0 + * + * Description: After the config file is read, the backend start function is called. + * This allows the backend writer to start any threads or perform any + * operations that need to be done after the config file has been read in. + * The ldif backend requires no such operations to be performed. + * + */ +int +ldif_back_start( Slapi_PBlock *pb ) +{ + return( 0 ); +} diff --git a/ldap/servers/slapd/back-ldif/unbind.c b/ldap/servers/slapd/back-ldif/unbind.c new file mode 100644 index 00000000..77c45adb --- /dev/null +++ b/ldap/servers/slapd/back-ldif/unbind.c @@ -0,0 +1,27 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * File: unbind.c + * + * Functions: + * + * ldif_back_unbind() - ldap ldif back-end unbind routine + * + */ +#include "back-ldif.h" + +/* + * Function: ldif_back_unbind + * + * Returns: returns 0 + * + * Description: performs an ldap unbind. + */ +int +ldif_back_unbind( Slapi_PBlock *pb ) +{ + return( 0 ); +} |
