1/* ldif.c - the ldif backend */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2005-2011 The OpenLDAP Foundation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted only as authorized by the OpenLDAP 10 * Public License. 11 * 12 * A copy of this license is available in the file LICENSE in the 13 * top-level directory of the distribution or, alternatively, at 14 * <http://www.OpenLDAP.org/license.html>. 15 */ 16/* ACKNOWLEDGEMENTS: 17 * This work was originally developed by Eric Stokes for inclusion 18 * in OpenLDAP Software. 19 */ 20 21#include "portable.h" 22#include <stdio.h> 23#include <ac/string.h> 24#include <sys/types.h> 25#include <sys/stat.h> 26#include <ac/dirent.h> 27#include <fcntl.h> 28#include <ac/errno.h> 29#include <ac/unistd.h> 30#include "slap.h" 31#include "lutil.h" 32#include "config.h" 33 34struct ldif_tool { 35 Entry **entries; /* collected by bi_tool_entry_first() */ 36 ID elen; /* length of entries[] array */ 37 ID ecount; /* number of entries */ 38 ID ecurrent; /* bi_tool_entry_next() position */ 39# define ENTRY_BUFF_INCREMENT 500 /* initial entries[] length */ 40 struct berval *tl_base; 41 int tl_scope; 42 Filter *tl_filter; 43}; 44 45/* Per-database data */ 46struct ldif_info { 47 struct berval li_base_path; /* database directory */ 48 struct ldif_tool li_tool; /* for slap tools */ 49 /* 50 * Read-only LDAP requests readlock li_rdwr for filesystem input. 51 * Update requests first lock li_modop_mutex for filesystem I/O, 52 * and then writelock li_rdwr as well for filesystem output. 53 * This allows update requests to do callbacks that acquire 54 * read locks, e.g. access controls that inspect entries. 55 * (An alternative would be recursive read/write locks.) 56 */ 57 ldap_pvt_thread_mutex_t li_modop_mutex; /* serialize update requests */ 58 ldap_pvt_thread_rdwr_t li_rdwr; /* no other I/O when writing */ 59}; 60 61static int write_data( int fd, const char *spew, int len, int *save_errno ); 62 63#ifdef _WIN32 64#define mkdir(a,b) mkdir(a) 65#define move_file(from, to) (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING)) 66#else 67#define move_file(from, to) rename(from, to) 68#endif 69#define move_dir(from, to) rename(from, to) 70 71 72#define LDIF ".ldif" 73#define LDIF_FILETYPE_SEP '.' /* LDIF[0] */ 74 75/* 76 * Unsafe/translated characters in the filesystem. 77 * 78 * LDIF_UNSAFE_CHAR(c) returns true if the character c is not to be used 79 * in relative filenames, except it should accept '\\', '{' and '}' even 80 * if unsafe. The value should be a constant expression. 81 * 82 * If '\\' is unsafe, #define LDIF_ESCAPE_CHAR as a safe character. 83 * If '{' and '}' are unsafe, #define IX_FSL/IX_FSR as safe characters. 84 * (Not digits, '-' or '+'. IX_FSL == IX_FSR is allowed.) 85 * 86 * Characters are escaped as LDIF_ESCAPE_CHAR followed by two hex digits, 87 * except '\\' is replaced with LDIF_ESCAPE_CHAR and {} with IX_FS[LR]. 88 * Also some LDIF special chars are hex-escaped. 89 * 90 * Thus an LDIF filename is a valid normalized RDN (or suffix DN) 91 * followed by ".ldif", except with '\\' replaced with LDIF_ESCAPE_CHAR. 92 */ 93 94#ifndef _WIN32 95 96/* 97 * Unix/MacOSX version. ':' vs '/' can cause confusion on MacOSX so we 98 * escape both. We escape them on Unix so both OS variants get the same 99 * filenames. 100 */ 101#define LDIF_ESCAPE_CHAR '\\' 102#define LDIF_UNSAFE_CHAR(c) ((c) == '/' || (c) == ':') 103 104#else /* _WIN32 */ 105 106/* Windows version - Microsoft's list of unsafe characters, except '\\' */ 107#define LDIF_ESCAPE_CHAR '^' /* Not '\\' (unsafe on Windows) */ 108#define LDIF_UNSAFE_CHAR(c) \ 109 ((c) == '/' || (c) == ':' || \ 110 (c) == '<' || (c) == '>' || (c) == '"' || \ 111 (c) == '|' || (c) == '?' || (c) == '*') 112 113#endif /* !_WIN32 */ 114 115/* 116 * Left and Right "{num}" prefix to ordered RDNs ("olcDatabase={1}bdb"). 117 * IX_DN* are for LDAP RDNs, IX_FS* for their .ldif filenames. 118 */ 119#define IX_DNL '{' 120#define IX_DNR '}' 121#ifndef IX_FSL 122#define IX_FSL IX_DNL 123#define IX_FSR IX_DNR 124#endif 125 126/* 127 * Test for unsafe chars, as well as chars handled specially by back-ldif: 128 * - If the escape char is not '\\', it must itself be escaped. Otherwise 129 * '\\' and the escape char would map to the same character. 130 * - Escape the '.' in ".ldif", so the directory for an RDN that actually 131 * ends with ".ldif" can not conflict with a file of the same name. And 132 * since some OSes/programs choke on multiple '.'s, escape all of them. 133 * - If '{' and '}' are translated to some other characters, those 134 * characters must in turn be escaped when they occur in an RDN. 135 */ 136#ifndef LDIF_NEED_ESCAPE 137#define LDIF_NEED_ESCAPE(c) \ 138 ((LDIF_UNSAFE_CHAR(c)) || \ 139 LDIF_MAYBE_UNSAFE(c, LDIF_ESCAPE_CHAR) || \ 140 LDIF_MAYBE_UNSAFE(c, LDIF_FILETYPE_SEP) || \ 141 LDIF_MAYBE_UNSAFE(c, IX_FSL) || \ 142 (IX_FSR != IX_FSL && LDIF_MAYBE_UNSAFE(c, IX_FSR))) 143#endif 144/* 145 * Helper macro for LDIF_NEED_ESCAPE(): Treat character x as unsafe if 146 * back-ldif does not already treat is specially. 147 */ 148#define LDIF_MAYBE_UNSAFE(c, x) \ 149 (!(LDIF_UNSAFE_CHAR(x) || (x) == '\\' || (x) == IX_DNL || (x) == IX_DNR) \ 150 && (c) == (x)) 151 152/* Collect other "safe char" tests here, until someone needs a fix. */ 153enum { 154 eq_unsafe = LDIF_UNSAFE_CHAR('='), 155 safe_filenames = STRLENOF("" LDAP_DIRSEP "") == 1 && !( 156 LDIF_UNSAFE_CHAR('-') || /* for "{-1}frontend" in bconfig.c */ 157 LDIF_UNSAFE_CHAR(LDIF_ESCAPE_CHAR) || 158 LDIF_UNSAFE_CHAR(IX_FSL) || LDIF_UNSAFE_CHAR(IX_FSR)) 159}; 160/* Sanity check: Try to force a compilation error if !safe_filenames */ 161typedef struct { 162 int assert_safe_filenames : safe_filenames ? 2 : -2; 163} assert_safe_filenames[safe_filenames ? 2 : -2]; 164 165 166static ConfigTable ldifcfg[] = { 167 { "directory", "dir", 2, 2, 0, ARG_BERVAL|ARG_OFFSET, 168 (void *)offsetof(struct ldif_info, li_base_path), 169 "( OLcfgDbAt:0.1 NAME 'olcDbDirectory' " 170 "DESC 'Directory for database content' " 171 "EQUALITY caseIgnoreMatch " 172 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 173 { NULL, NULL, 0, 0, 0, ARG_IGNORED, 174 NULL, NULL, NULL, NULL } 175}; 176 177static ConfigOCs ldifocs[] = { 178 { "( OLcfgDbOc:2.1 " 179 "NAME 'olcLdifConfig' " 180 "DESC 'LDIF backend configuration' " 181 "SUP olcDatabaseConfig " 182 "MUST ( olcDbDirectory ) )", Cft_Database, ldifcfg }, 183 { NULL, 0, NULL } 184}; 185 186 187/* 188 * Handle file/directory names. 189 */ 190 191/* Set *res = LDIF filename path for the normalized DN */ 192static int 193ndn2path( Operation *op, struct berval *dn, struct berval *res, int empty_ok ) 194{ 195 BackendDB *be = op->o_bd; 196 struct ldif_info *li = (struct ldif_info *) be->be_private; 197 struct berval *suffixdn = &be->be_nsuffix[0]; 198 const char *start, *end, *next, *p; 199 char ch, *ptr; 200 ber_len_t len; 201 static const char hex[] = "0123456789ABCDEF"; 202 203 assert( dn != NULL ); 204 assert( !BER_BVISNULL( dn ) ); 205 assert( suffixdn != NULL ); 206 assert( !BER_BVISNULL( suffixdn ) ); 207 assert( dnIsSuffix( dn, suffixdn ) ); 208 209 if ( dn->bv_len == 0 && !empty_ok ) { 210 return LDAP_UNWILLING_TO_PERFORM; 211 } 212 213 start = dn->bv_val; 214 end = start + dn->bv_len; 215 216 /* Room for dir, dirsep, dn, LDIF, "\hexpair"-escaping of unsafe chars */ 217 len = li->li_base_path.bv_len + dn->bv_len + (1 + STRLENOF( LDIF )); 218 for ( p = start; p < end; ) { 219 ch = *p++; 220 if ( LDIF_NEED_ESCAPE( ch ) ) 221 len += 2; 222 } 223 res->bv_val = ch_malloc( len + 1 ); 224 225 ptr = lutil_strcopy( res->bv_val, li->li_base_path.bv_val ); 226 for ( next = end - suffixdn->bv_len; end > start; end = next ) { 227 /* Set p = start of DN component, next = &',' or start of DN */ 228 while ( (p = next) > start ) { 229 --next; 230 if ( DN_SEPARATOR( *next ) ) 231 break; 232 } 233 /* Append <dirsep> <p..end-1: RDN or database-suffix> */ 234 for ( *ptr++ = LDAP_DIRSEP[0]; p < end; *ptr++ = ch ) { 235 ch = *p++; 236 if ( LDIF_ESCAPE_CHAR != '\\' && ch == '\\' ) { 237 ch = LDIF_ESCAPE_CHAR; 238 } else if ( IX_FSL != IX_DNL && ch == IX_DNL ) { 239 ch = IX_FSL; 240 } else if ( IX_FSR != IX_DNR && ch == IX_DNR ) { 241 ch = IX_FSR; 242 } else if ( LDIF_NEED_ESCAPE( ch ) ) { 243 *ptr++ = LDIF_ESCAPE_CHAR; 244 *ptr++ = hex[(ch & 0xFFU) >> 4]; 245 ch = hex[ch & 0x0FU]; 246 } 247 } 248 } 249 ptr = lutil_strcopy( ptr, LDIF ); 250 res->bv_len = ptr - res->bv_val; 251 252 assert( res->bv_len <= len ); 253 254 return LDAP_SUCCESS; 255} 256 257/* 258 * *dest = dupbv(<dir + LDAP_DIRSEP>), plus room for <more>-sized filename. 259 * Return pointer past the dirname. 260 */ 261static char * 262fullpath_alloc( struct berval *dest, const struct berval *dir, ber_len_t more ) 263{ 264 char *s = SLAP_MALLOC( dir->bv_len + more + 2 ); 265 266 dest->bv_val = s; 267 if ( s == NULL ) { 268 dest->bv_len = 0; 269 Debug( LDAP_DEBUG_ANY, "back-ldif: out of memory\n", 0, 0, 0 ); 270 } else { 271 s = lutil_strcopy( dest->bv_val, dir->bv_val ); 272 *s++ = LDAP_DIRSEP[0]; 273 *s = '\0'; 274 dest->bv_len = s - dest->bv_val; 275 } 276 return s; 277} 278 279/* 280 * Append filename to fullpath_alloc() dirname or replace previous filename. 281 * dir_end = fullpath_alloc() return value. 282 */ 283#define FILL_PATH(fpath, dir_end, filename) \ 284 ((fpath)->bv_len = lutil_strcopy(dir_end, filename) - (fpath)->bv_val) 285 286 287/* .ldif entry filename length <-> subtree dirname length. */ 288#define ldif2dir_len(bv) ((bv).bv_len -= STRLENOF(LDIF)) 289#define dir2ldif_len(bv) ((bv).bv_len += STRLENOF(LDIF)) 290/* .ldif entry filename <-> subtree dirname, both with dirname length. */ 291#define ldif2dir_name(bv) ((bv).bv_val[(bv).bv_len] = '\0') 292#define dir2ldif_name(bv) ((bv).bv_val[(bv).bv_len] = LDIF_FILETYPE_SEP) 293 294/* Get the parent directory path, plus the LDIF suffix overwritten by a \0. */ 295static int 296get_parent_path( struct berval *dnpath, struct berval *res ) 297{ 298 ber_len_t i = dnpath->bv_len; 299 300 while ( i > 0 && dnpath->bv_val[ --i ] != LDAP_DIRSEP[0] ) ; 301 if ( res == NULL ) { 302 res = dnpath; 303 } else { 304 res->bv_val = SLAP_MALLOC( i + 1 + STRLENOF(LDIF) ); 305 if ( res->bv_val == NULL ) 306 return LDAP_OTHER; 307 AC_MEMCPY( res->bv_val, dnpath->bv_val, i ); 308 } 309 res->bv_len = i; 310 strcpy( res->bv_val + i, LDIF ); 311 res->bv_val[i] = '\0'; 312 return LDAP_SUCCESS; 313} 314 315/* Make temporary filename pattern for mkstemp() based on dnpath. */ 316static char * 317ldif_tempname( const struct berval *dnpath ) 318{ 319 static const char suffix[] = ".XXXXXX"; 320 ber_len_t len = dnpath->bv_len - STRLENOF( LDIF ); 321 char *name = SLAP_MALLOC( len + sizeof( suffix ) ); 322 323 if ( name != NULL ) { 324 AC_MEMCPY( name, dnpath->bv_val, len ); 325 strcpy( name + len, suffix ); 326 } 327 return name; 328} 329 330/* CRC-32 table for the polynomial: 331 * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. 332 * 333 * As used by zlib 334 */ 335 336static const ber_uint_t crctab[256] = { 337 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 338 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 339 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 340 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 341 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 342 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 343 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 344 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 345 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 346 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 347 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 348 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 349 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 350 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 351 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 352 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 353 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 354 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 355 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 356 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 357 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 358 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 359 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 360 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 361 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 362 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 363 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 364 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 365 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 366 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 367 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 368 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 369 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 370 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 371 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 372 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 373 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 374 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 375 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 376 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 377 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 378 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 379 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 380 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 381 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 382 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 383 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 384 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 385 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 386 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 387 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 388 0x2d02ef8dL 389}; 390 391#define CRC1 crc = crctab[(crc ^ *buf++) & 0xff] ^ (crc >> 8) 392#define CRC8 CRC1; CRC1; CRC1; CRC1; CRC1; CRC1; CRC1; CRC1 393unsigned int 394crc32(const void *vbuf, int len) 395{ 396 const unsigned char *buf = vbuf; 397 ber_uint_t crc = 0xffffffff; 398 int i; 399 400 while (len > 7) { 401 CRC8; 402 len -= 8; 403 } 404 while (len) { 405 CRC1; 406 len--; 407 } 408 409 return crc ^ 0xffffffff; 410} 411 412/* 413 * Read a file, or stat() it if datap == NULL. Allocate and fill *datap. 414 * Return LDAP_SUCCESS, LDAP_NO_SUCH_OBJECT (no such file), or another error. 415 */ 416static int 417ldif_read_file( const char *path, char **datap ) 418{ 419 int rc = LDAP_SUCCESS, fd, len; 420 int res = -1; /* 0:success, <0:error, >0:file too big/growing. */ 421 struct stat st; 422 char *data = NULL, *ptr = NULL; 423 const char *msg; 424 425 if ( datap == NULL ) { 426 res = stat( path, &st ); 427 goto done; 428 } 429 fd = open( path, O_RDONLY ); 430 if ( fd >= 0 ) { 431 if ( fstat( fd, &st ) == 0 ) { 432 if ( st.st_size > INT_MAX - 2 ) { 433 res = 1; 434 } else { 435 len = st.st_size + 1; /* +1 detects file size > st.st_size */ 436 *datap = data = ptr = SLAP_MALLOC( len + 1 ); 437 if ( ptr != NULL ) { 438 while ( len && (res = read( fd, ptr, len )) ) { 439 if ( res > 0 ) { 440 len -= res; 441 ptr += res; 442 } else if ( errno != EINTR ) { 443 break; 444 } 445 } 446 *ptr = '\0'; 447 } 448 } 449 } 450 if ( close( fd ) < 0 ) 451 res = -1; 452 } 453 454 done: 455 if ( res == 0 ) { 456#ifdef LDAP_DEBUG 457 msg = "entry file exists"; 458 if ( datap ) { 459 msg = "read entry file"; 460 len = ptr - data; 461 ptr = strstr( data, "\n# CRC32" ); 462 if (!ptr) { 463 msg = "read entry file without checksum"; 464 } else { 465 unsigned int crc1 = 0, crc2 = 1; 466 if ( sscanf( ptr + 9, "%08x", &crc1) == 1) { 467 ptr = strchr(ptr+1, '\n'); 468 if ( ptr ) { 469 ptr++; 470 len -= (ptr - data); 471 crc2 = crc32( ptr, len ); 472 } 473 } 474 if ( crc1 != crc2 ) { 475 Debug( LDAP_DEBUG_ANY, "ldif_read_file: checksum error on \"%s\"\n", 476 path, 0, 0 ); 477 return rc; 478 } 479 } 480 } 481 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: %s: \"%s\"\n", msg, path, 0 ); 482#endif /* LDAP_DEBUG */ 483 } else { 484 if ( res < 0 && errno == ENOENT ) { 485 Debug( LDAP_DEBUG_TRACE, "ldif_read_file: " 486 "no entry file \"%s\"\n", path, 0, 0 ); 487 rc = LDAP_NO_SUCH_OBJECT; 488 } else { 489 msg = res < 0 ? STRERROR( errno ) : "bad stat() size"; 490 Debug( LDAP_DEBUG_ANY, "ldif_read_file: %s for \"%s\"\n", 491 msg, path, 0 ); 492 rc = LDAP_OTHER; 493 } 494 if ( data != NULL ) 495 SLAP_FREE( data ); 496 } 497 return rc; 498} 499 500/* 501 * return nonnegative for success or -1 for error 502 * do not return numbers less than -1 503 */ 504static int 505spew_file( int fd, const char *spew, int len, int *save_errno ) 506{ 507 int writeres; 508#define HEADER "# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.\n" 509 char header[sizeof(HEADER "# CRC32 12345678\n")]; 510 511 sprintf(header, HEADER "# CRC32 %08x\n", crc32(spew, len)); 512 writeres = write_data(fd, header, sizeof(header)-1, save_errno); 513 return writeres < 0 ? writeres : write_data(fd, spew, len, save_errno); 514} 515 516static int 517write_data( int fd, const char *spew, int len, int *save_errno ) 518{ 519 int writeres = 0; 520 while(len > 0) { 521 writeres = write(fd, spew, len); 522 if(writeres == -1) { 523 *save_errno = errno; 524 if (*save_errno != EINTR) 525 break; 526 } 527 else { 528 spew += writeres; 529 len -= writeres; 530 } 531 } 532 return writeres; 533} 534 535/* Write an entry LDIF file. Create parentdir first if non-NULL. */ 536static int 537ldif_write_entry( 538 Operation *op, 539 Entry *e, 540 const struct berval *path, 541 const char *parentdir, 542 const char **text ) 543{ 544 int rc = LDAP_OTHER, res, save_errno = 0; 545 int fd, entry_length; 546 char *entry_as_string, *tmpfname; 547 548 if ( op->o_abandon ) 549 return SLAPD_ABANDON; 550 551 if ( parentdir != NULL && mkdir( parentdir, 0750 ) < 0 ) { 552 save_errno = errno; 553 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n", 554 "cannot create parent directory", 555 parentdir, STRERROR( save_errno ) ); 556 *text = "internal error (cannot create parent directory)"; 557 return rc; 558 } 559 560 tmpfname = ldif_tempname( path ); 561 fd = tmpfname == NULL ? -1 : mkstemp( tmpfname ); 562 if ( fd < 0 ) { 563 save_errno = errno; 564 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s for \"%s\": %s\n", 565 "cannot create file", e->e_dn, STRERROR( save_errno ) ); 566 *text = "internal error (cannot create file)"; 567 568 } else { 569 ber_len_t dn_len = e->e_name.bv_len; 570 struct berval rdn; 571 572 /* Only save the RDN onto disk */ 573 dnRdn( &e->e_name, &rdn ); 574 if ( rdn.bv_len != dn_len ) { 575 e->e_name.bv_val[rdn.bv_len] = '\0'; 576 e->e_name.bv_len = rdn.bv_len; 577 } 578 579 res = -2; 580 ldap_pvt_thread_mutex_lock( &entry2str_mutex ); 581 entry_as_string = entry2str( e, &entry_length ); 582 if ( entry_as_string != NULL ) 583 res = spew_file( fd, entry_as_string, entry_length, &save_errno ); 584 ldap_pvt_thread_mutex_unlock( &entry2str_mutex ); 585 586 /* Restore full DN */ 587 if ( rdn.bv_len != dn_len ) { 588 e->e_name.bv_val[rdn.bv_len] = ','; 589 e->e_name.bv_len = dn_len; 590 } 591 592 if ( close( fd ) < 0 && res >= 0 ) { 593 res = -1; 594 save_errno = errno; 595 } 596 597 if ( res >= 0 ) { 598 if ( move_file( tmpfname, path->bv_val ) == 0 ) { 599 Debug( LDAP_DEBUG_TRACE, "ldif_write_entry: " 600 "wrote entry \"%s\"\n", e->e_name.bv_val, 0, 0 ); 601 rc = LDAP_SUCCESS; 602 } else { 603 save_errno = errno; 604 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: " 605 "could not put entry file for \"%s\" in place: %s\n", 606 e->e_name.bv_val, STRERROR( save_errno ), 0 ); 607 *text = "internal error (could not put entry file in place)"; 608 } 609 } else if ( res == -1 ) { 610 Debug( LDAP_DEBUG_ANY, "ldif_write_entry: %s \"%s\": %s\n", 611 "write error to", tmpfname, STRERROR( save_errno ) ); 612 *text = "internal error (write error to entry file)"; 613 } 614 615 if ( rc != LDAP_SUCCESS ) { 616 unlink( tmpfname ); 617 } 618 } 619 620 if ( tmpfname ) 621 SLAP_FREE( tmpfname ); 622 return rc; 623} 624 625/* 626 * Read the entry at path, or if entryp==NULL just see if it exists. 627 * pdn and pndn are the parent's DN and normalized DN, or both NULL. 628 * Return an LDAP result code. 629 */ 630static int 631ldif_read_entry( 632 Operation *op, 633 const char *path, 634 struct berval *pdn, 635 struct berval *pndn, 636 Entry **entryp, 637 const char **text ) 638{ 639 int rc; 640 Entry *entry; 641 char *entry_as_string; 642 struct berval rdn; 643 644 /* TODO: Does slapd prevent Abandon of Bind as per rfc4511? 645 * If so we need not check for LDAP_REQ_BIND here. 646 */ 647 if ( op->o_abandon && op->o_tag != LDAP_REQ_BIND ) 648 return SLAPD_ABANDON; 649 650 rc = ldif_read_file( path, entryp ? &entry_as_string : NULL ); 651 652 switch ( rc ) { 653 case LDAP_SUCCESS: 654 if ( entryp == NULL ) 655 break; 656 *entryp = entry = str2entry( entry_as_string ); 657 SLAP_FREE( entry_as_string ); 658 if ( entry == NULL ) { 659 rc = LDAP_OTHER; 660 if ( text != NULL ) 661 *text = "internal error (cannot parse some entry file)"; 662 break; 663 } 664 if ( pdn == NULL || BER_BVISEMPTY( pdn ) ) 665 break; 666 /* Append parent DN to DN from LDIF file */ 667 rdn = entry->e_name; 668 build_new_dn( &entry->e_name, pdn, &rdn, NULL ); 669 SLAP_FREE( rdn.bv_val ); 670 rdn = entry->e_nname; 671 build_new_dn( &entry->e_nname, pndn, &rdn, NULL ); 672 SLAP_FREE( rdn.bv_val ); 673 break; 674 675 case LDAP_OTHER: 676 if ( text != NULL ) 677 *text = entryp 678 ? "internal error (cannot read some entry file)" 679 : "internal error (cannot stat some entry file)"; 680 break; 681 } 682 683 return rc; 684} 685 686/* 687 * Read the operation's entry, or if entryp==NULL just see if it exists. 688 * Return an LDAP result code. May set *text to a message on failure. 689 * If pathp is non-NULL, set it to the entry filename on success. 690 */ 691static int 692get_entry( 693 Operation *op, 694 Entry **entryp, 695 struct berval *pathp, 696 const char **text ) 697{ 698 int rc; 699 struct berval path, pdn, pndn; 700 701 dnParent( &op->o_req_dn, &pdn ); 702 dnParent( &op->o_req_ndn, &pndn ); 703 rc = ndn2path( op, &op->o_req_ndn, &path, 0 ); 704 if ( rc != LDAP_SUCCESS ) { 705 goto done; 706 } 707 708 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, entryp, text ); 709 710 if ( rc == LDAP_SUCCESS && pathp != NULL ) { 711 *pathp = path; 712 } else { 713 SLAP_FREE( path.bv_val ); 714 } 715 done: 716 return rc; 717} 718 719 720/* 721 * RDN-named directory entry, with special handling of "attr={num}val" RDNs. 722 * For sorting, filename "attr=val.ldif" is truncated to "attr="val\0ldif", 723 * and filename "attr={num}val.ldif" to "attr={\0um}val.ldif". 724 * Does not sort escaped chars correctly, would need to un-escape them. 725 */ 726typedef struct bvlist { 727 struct bvlist *next; 728 char *trunc; /* filename was truncated here */ 729 int inum; /* num from "attr={num}" in filename, or INT_MIN */ 730 char savech; /* original char at *trunc */ 731 /* BVL_NAME(&bvlist) is the filename, allocated after the struct: */ 732# define BVL_NAME(bvl) ((char *) ((bvl) + 1)) 733# define BVL_SIZE(namelen) (sizeof(bvlist) + (namelen) + 1) 734} bvlist; 735 736static int 737ldif_send_entry( Operation *op, SlapReply *rs, Entry *e, int scope ) 738{ 739 int rc = LDAP_SUCCESS; 740 741 if ( scope == LDAP_SCOPE_BASE || scope == LDAP_SCOPE_SUBTREE ) { 742 if ( rs == NULL ) { 743 /* Save the entry for tool mode */ 744 struct ldif_tool *tl = 745 &((struct ldif_info *) op->o_bd->be_private)->li_tool; 746 747 if ( tl->ecount >= tl->elen ) { 748 /* Allocate/grow entries */ 749 ID elen = tl->elen ? tl->elen * 2 : ENTRY_BUFF_INCREMENT; 750 Entry **entries = (Entry **) SLAP_REALLOC( tl->entries, 751 sizeof(Entry *) * elen ); 752 if ( entries == NULL ) { 753 Debug( LDAP_DEBUG_ANY, 754 "ldif_send_entry: out of memory\n", 0, 0, 0 ); 755 rc = LDAP_OTHER; 756 goto done; 757 } 758 tl->elen = elen; 759 tl->entries = entries; 760 } 761 tl->entries[tl->ecount++] = e; 762 return rc; 763 } 764 765 else if ( !get_manageDSAit( op ) && is_entry_referral( e ) ) { 766 /* Send a continuation reference. 767 * (ldif_back_referrals() handles baseobject referrals.) 768 * Don't check the filter since it's only a candidate. 769 */ 770 BerVarray refs = get_entry_referrals( op, e ); 771 rs->sr_ref = referral_rewrite( refs, &e->e_name, NULL, scope ); 772 rs->sr_entry = e; 773 rc = send_search_reference( op, rs ); 774 ber_bvarray_free( rs->sr_ref ); 775 ber_bvarray_free( refs ); 776 rs->sr_ref = NULL; 777 rs->sr_entry = NULL; 778 } 779 780 else if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) { 781 rs->sr_entry = e; 782 rs->sr_attrs = op->ors_attrs; 783 /* Could set REP_ENTRY_MUSTBEFREED too for efficiency, 784 * but refraining lets us test unFREEable MODIFIABLE 785 * entries. Like entries built on the stack. 786 */ 787 rs->sr_flags = REP_ENTRY_MODIFIABLE; 788 rc = send_search_entry( op, rs ); 789 rs->sr_entry = NULL; 790 rs->sr_attrs = NULL; 791 } 792 } 793 794 done: 795 entry_free( e ); 796 return rc; 797} 798 799/* Read LDIF directory <path> into <listp>. Set *fname_maxlenp. */ 800static int 801ldif_readdir( 802 Operation *op, 803 SlapReply *rs, 804 const struct berval *path, 805 bvlist **listp, 806 ber_len_t *fname_maxlenp ) 807{ 808 int rc = LDAP_SUCCESS; 809 DIR *dir_of_path; 810 811 *listp = NULL; 812 *fname_maxlenp = 0; 813 814 dir_of_path = opendir( path->bv_val ); 815 if ( dir_of_path == NULL ) { 816 int save_errno = errno; 817 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private; 818 int is_rootDSE = (path->bv_len == li->li_base_path.bv_len); 819 820 /* Absent directory is OK (leaf entry), except the database dir */ 821 if ( is_rootDSE || save_errno != ENOENT ) { 822 Debug( LDAP_DEBUG_ANY, 823 "=> ldif_search_entry: failed to opendir \"%s\": %s\n", 824 path->bv_val, STRERROR( save_errno ), 0 ); 825 rc = LDAP_OTHER; 826 if ( rs != NULL ) 827 rs->sr_text = 828 save_errno != ENOENT ? "internal error (bad directory)" 829 : !is_rootDSE ? "internal error (missing directory)" 830 : "internal error (database directory does not exist)"; 831 } 832 833 } else { 834 bvlist *ptr; 835 struct dirent *dir; 836 int save_errno = 0; 837 838 while ( (dir = readdir( dir_of_path )) != NULL ) { 839 size_t fname_len; 840 bvlist *bvl, **prev; 841 char *trunc, *idxp, *endp, *endp2; 842 843 fname_len = strlen( dir->d_name ); 844 if ( fname_len < STRLENOF( "x=" LDIF )) /* min filename size */ 845 continue; 846 if ( strcmp( dir->d_name + fname_len - STRLENOF(LDIF), LDIF )) 847 continue; 848 849 if ( *fname_maxlenp < fname_len ) 850 *fname_maxlenp = fname_len; 851 852 bvl = SLAP_MALLOC( BVL_SIZE( fname_len ) ); 853 if ( bvl == NULL ) { 854 rc = LDAP_OTHER; 855 save_errno = errno; 856 break; 857 } 858 strcpy( BVL_NAME( bvl ), dir->d_name ); 859 860 /* Make it sortable by ("attr=val" or <preceding {num}, num>) */ 861 trunc = BVL_NAME( bvl ) + fname_len - STRLENOF( LDIF ); 862 if ( (idxp = strchr( BVL_NAME( bvl ) + 2, IX_FSL )) != NULL && 863 (endp = strchr( ++idxp, IX_FSR )) != NULL && endp > idxp && 864 (eq_unsafe || idxp[-2] == '=' || endp + 1 == trunc) ) 865 { 866 /* attr={n}val or bconfig.c's "pseudo-indexed" attr=val{n} */ 867 bvl->inum = strtol( idxp, &endp2, 10 ); 868 if ( endp2 == endp ) { 869 trunc = idxp; 870 goto truncate; 871 } 872 } 873 bvl->inum = INT_MIN; 874 truncate: 875 bvl->trunc = trunc; 876 bvl->savech = *trunc; 877 *trunc = '\0'; 878 879 /* Insertion sort */ 880 for ( prev = listp; (ptr = *prev) != NULL; prev = &ptr->next ) { 881 int cmp = strcmp( BVL_NAME( bvl ), BVL_NAME( ptr )); 882 if ( cmp < 0 || (cmp == 0 && bvl->inum < ptr->inum) ) 883 break; 884 } 885 *prev = bvl; 886 bvl->next = ptr; 887 } 888 889 if ( closedir( dir_of_path ) < 0 ) { 890 save_errno = errno; 891 rc = LDAP_OTHER; 892 if ( rs != NULL ) 893 rs->sr_text = "internal error (bad directory)"; 894 } 895 if ( rc != LDAP_SUCCESS ) { 896 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: %s \"%s\": %s\n", 897 "error reading directory", path->bv_val, 898 STRERROR( save_errno ) ); 899 } 900 } 901 902 return rc; 903} 904 905/* 906 * Send an entry, recursively search its children, and free or save it. 907 * Return an LDAP result code. Parameters: 908 * op, rs operation and reply. rs == NULL for slap tools. 909 * e entry to search, or NULL for rootDSE. 910 * scope scope for the part of the search from this entry. 911 * path LDIF filename -- bv_len and non-directory part are overwritten. 912 */ 913static int 914ldif_search_entry( 915 Operation *op, 916 SlapReply *rs, 917 Entry *e, 918 int scope, 919 struct berval *path ) 920{ 921 int rc = LDAP_SUCCESS; 922 struct berval dn = BER_BVC( "" ), ndn = BER_BVC( "" ); 923 924 if ( scope != LDAP_SCOPE_BASE && e != NULL ) { 925 /* Copy DN/NDN since we send the entry with REP_ENTRY_MODIFIABLE, 926 * which bconfig.c seems to need. (TODO: see config_rename_one.) 927 */ 928 if ( ber_dupbv( &dn, &e->e_name ) == NULL || 929 ber_dupbv( &ndn, &e->e_nname ) == NULL ) 930 { 931 Debug( LDAP_DEBUG_ANY, 932 "ldif_search_entry: out of memory\n", 0, 0, 0 ); 933 rc = LDAP_OTHER; 934 goto done; 935 } 936 } 937 938 /* Send the entry if appropriate, and free or save it */ 939 if ( e != NULL ) 940 rc = ldif_send_entry( op, rs, e, scope ); 941 942 /* Search the children */ 943 if ( scope != LDAP_SCOPE_BASE && rc == LDAP_SUCCESS ) { 944 bvlist *list, *ptr; 945 struct berval fpath; /* becomes child pathname */ 946 char *dir_end; /* will point past dirname in fpath */ 947 948 ldif2dir_len( *path ); 949 ldif2dir_name( *path ); 950 rc = ldif_readdir( op, rs, path, &list, &fpath.bv_len ); 951 952 if ( list != NULL ) { 953 const char **text = rs == NULL ? NULL : &rs->sr_text; 954 955 if ( scope == LDAP_SCOPE_ONELEVEL ) 956 scope = LDAP_SCOPE_BASE; 957 else if ( scope == LDAP_SCOPE_SUBORDINATE ) 958 scope = LDAP_SCOPE_SUBTREE; 959 960 /* Allocate fpath and fill in directory part */ 961 dir_end = fullpath_alloc( &fpath, path, fpath.bv_len ); 962 if ( dir_end == NULL ) 963 rc = LDAP_OTHER; 964 965 do { 966 ptr = list; 967 968 if ( rc == LDAP_SUCCESS ) { 969 *ptr->trunc = ptr->savech; 970 FILL_PATH( &fpath, dir_end, BVL_NAME( ptr )); 971 972 rc = ldif_read_entry( op, fpath.bv_val, &dn, &ndn, 973 &e, text ); 974 switch ( rc ) { 975 case LDAP_SUCCESS: 976 rc = ldif_search_entry( op, rs, e, scope, &fpath ); 977 break; 978 case LDAP_NO_SUCH_OBJECT: 979 /* Only the search baseDN may produce noSuchObject. */ 980 rc = LDAP_OTHER; 981 if ( rs != NULL ) 982 rs->sr_text = "internal error " 983 "(did someone just remove an entry file?)"; 984 Debug( LDAP_DEBUG_ANY, "ldif_search_entry: " 985 "file listed in parent directory does not exist: " 986 "\"%s\"\n", fpath.bv_val, 0, 0 ); 987 break; 988 } 989 } 990 991 list = ptr->next; 992 SLAP_FREE( ptr ); 993 } while ( list != NULL ); 994 995 if ( !BER_BVISNULL( &fpath ) ) 996 SLAP_FREE( fpath.bv_val ); 997 } 998 } 999 1000 done: 1001 if ( !BER_BVISEMPTY( &dn ) ) 1002 ber_memfree( dn.bv_val ); 1003 if ( !BER_BVISEMPTY( &ndn ) ) 1004 ber_memfree( ndn.bv_val ); 1005 return rc; 1006} 1007 1008static int 1009search_tree( Operation *op, SlapReply *rs ) 1010{ 1011 int rc = LDAP_SUCCESS; 1012 Entry *e = NULL; 1013 struct berval path; 1014 struct berval pdn, pndn; 1015 1016 (void) ndn2path( op, &op->o_req_ndn, &path, 1 ); 1017 if ( !BER_BVISEMPTY( &op->o_req_ndn ) ) { 1018 /* Read baseObject */ 1019 dnParent( &op->o_req_dn, &pdn ); 1020 dnParent( &op->o_req_ndn, &pndn ); 1021 rc = ldif_read_entry( op, path.bv_val, &pdn, &pndn, &e, 1022 rs == NULL ? NULL : &rs->sr_text ); 1023 } 1024 if ( rc == LDAP_SUCCESS ) 1025 rc = ldif_search_entry( op, rs, e, op->ors_scope, &path ); 1026 1027 ch_free( path.bv_val ); 1028 return rc; 1029} 1030 1031 1032/* 1033 * Prepare to create or rename an entry: 1034 * Check that the entry does not already exist. 1035 * Check that the parent entry exists and can have subordinates, 1036 * unless need_dir is NULL or adding the suffix entry. 1037 * 1038 * Return an LDAP result code. May set *text to a message on failure. 1039 * If success, set *dnpath to LDIF entry path and *need_dir to 1040 * (directory must be created ? dirname : NULL). 1041 */ 1042static int 1043ldif_prepare_create( 1044 Operation *op, 1045 Entry *e, 1046 struct berval *dnpath, 1047 char **need_dir, 1048 const char **text ) 1049{ 1050 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private; 1051 struct berval *ndn = &e->e_nname; 1052 struct berval ppath = BER_BVNULL; 1053 struct stat st; 1054 Entry *parent = NULL; 1055 int rc; 1056 1057 if ( op->o_abandon ) 1058 return SLAPD_ABANDON; 1059 1060 rc = ndn2path( op, ndn, dnpath, 0 ); 1061 if ( rc != LDAP_SUCCESS ) { 1062 return rc; 1063 } 1064 1065 if ( stat( dnpath->bv_val, &st ) == 0 ) { /* entry .ldif file */ 1066 rc = LDAP_ALREADY_EXISTS; 1067 1068 } else if ( errno != ENOENT ) { 1069 Debug( LDAP_DEBUG_ANY, 1070 "ldif_prepare_create: cannot stat \"%s\": %s\n", 1071 dnpath->bv_val, STRERROR( errno ), 0 ); 1072 rc = LDAP_OTHER; 1073 *text = "internal error (cannot check entry file)"; 1074 1075 } else if ( need_dir != NULL ) { 1076 *need_dir = NULL; 1077 rc = get_parent_path( dnpath, &ppath ); 1078 /* If parent dir exists, so does parent .ldif: 1079 * The directory gets created after and removed before the .ldif. 1080 * Except with the database directory, which has no matching entry. 1081 */ 1082 if ( rc == LDAP_SUCCESS && stat( ppath.bv_val, &st ) < 0 ) { 1083 rc = errno == ENOENT && ppath.bv_len > li->li_base_path.bv_len 1084 ? LDAP_NO_SUCH_OBJECT : LDAP_OTHER; 1085 } 1086 switch ( rc ) { 1087 case LDAP_NO_SUCH_OBJECT: 1088 /* No parent dir, check parent .ldif */ 1089 dir2ldif_name( ppath ); 1090 rc = ldif_read_entry( op, ppath.bv_val, NULL, NULL, 1091 (op->o_tag != LDAP_REQ_ADD || get_manageDSAit( op ) 1092 ? &parent : NULL), 1093 text ); 1094 switch ( rc ) { 1095 case LDAP_SUCCESS: 1096 /* Check that parent is not a referral, unless 1097 * ldif_back_referrals() already checked. 1098 */ 1099 if ( parent != NULL ) { 1100 int is_ref = is_entry_referral( parent ); 1101 entry_free( parent ); 1102 if ( is_ref ) { 1103 rc = LDAP_AFFECTS_MULTIPLE_DSAS; 1104 *text = op->o_tag == LDAP_REQ_MODDN 1105 ? "newSuperior is a referral object" 1106 : "parent is a referral object"; 1107 break; 1108 } 1109 } 1110 /* Must create parent directory. */ 1111 ldif2dir_name( ppath ); 1112 *need_dir = ppath.bv_val; 1113 break; 1114 case LDAP_NO_SUCH_OBJECT: 1115 *text = op->o_tag == LDAP_REQ_MODDN 1116 ? "newSuperior object does not exist" 1117 : "parent does not exist"; 1118 break; 1119 } 1120 break; 1121 case LDAP_OTHER: 1122 Debug( LDAP_DEBUG_ANY, 1123 "ldif_prepare_create: cannot stat \"%s\" parent dir: %s\n", 1124 ndn->bv_val, STRERROR( errno ), 0 ); 1125 *text = "internal error (cannot stat parent dir)"; 1126 break; 1127 } 1128 if ( *need_dir == NULL && ppath.bv_val != NULL ) 1129 SLAP_FREE( ppath.bv_val ); 1130 } 1131 1132 if ( rc != LDAP_SUCCESS ) { 1133 SLAP_FREE( dnpath->bv_val ); 1134 BER_BVZERO( dnpath ); 1135 } 1136 return rc; 1137} 1138 1139static int 1140apply_modify_to_entry( 1141 Entry *entry, 1142 Modifications *modlist, 1143 Operation *op, 1144 SlapReply *rs, 1145 char *textbuf ) 1146{ 1147 int rc = modlist ? LDAP_UNWILLING_TO_PERFORM : LDAP_SUCCESS; 1148 int is_oc = 0; 1149 Modification *mods; 1150 1151 if (!acl_check_modlist(op, entry, modlist)) { 1152 return LDAP_INSUFFICIENT_ACCESS; 1153 } 1154 1155 for (; modlist != NULL; modlist = modlist->sml_next) { 1156 mods = &modlist->sml_mod; 1157 1158 if ( mods->sm_desc == slap_schema.si_ad_objectClass ) { 1159 is_oc = 1; 1160 } 1161 switch (mods->sm_op) { 1162 case LDAP_MOD_ADD: 1163 rc = modify_add_values(entry, mods, 1164 get_permissiveModify(op), 1165 &rs->sr_text, textbuf, 1166 SLAP_TEXT_BUFLEN ); 1167 break; 1168 1169 case LDAP_MOD_DELETE: 1170 rc = modify_delete_values(entry, mods, 1171 get_permissiveModify(op), 1172 &rs->sr_text, textbuf, 1173 SLAP_TEXT_BUFLEN ); 1174 break; 1175 1176 case LDAP_MOD_REPLACE: 1177 rc = modify_replace_values(entry, mods, 1178 get_permissiveModify(op), 1179 &rs->sr_text, textbuf, 1180 SLAP_TEXT_BUFLEN ); 1181 break; 1182 1183 case LDAP_MOD_INCREMENT: 1184 rc = modify_increment_values( entry, 1185 mods, get_permissiveModify(op), 1186 &rs->sr_text, textbuf, 1187 SLAP_TEXT_BUFLEN ); 1188 break; 1189 1190 case SLAP_MOD_SOFTADD: 1191 mods->sm_op = LDAP_MOD_ADD; 1192 rc = modify_add_values(entry, mods, 1193 get_permissiveModify(op), 1194 &rs->sr_text, textbuf, 1195 SLAP_TEXT_BUFLEN ); 1196 mods->sm_op = SLAP_MOD_SOFTADD; 1197 if (rc == LDAP_TYPE_OR_VALUE_EXISTS) { 1198 rc = LDAP_SUCCESS; 1199 } 1200 break; 1201 1202 case SLAP_MOD_SOFTDEL: 1203 mods->sm_op = LDAP_MOD_DELETE; 1204 rc = modify_delete_values(entry, mods, 1205 get_permissiveModify(op), 1206 &rs->sr_text, textbuf, 1207 SLAP_TEXT_BUFLEN ); 1208 mods->sm_op = SLAP_MOD_SOFTDEL; 1209 if (rc == LDAP_NO_SUCH_ATTRIBUTE) { 1210 rc = LDAP_SUCCESS; 1211 } 1212 break; 1213 1214 case SLAP_MOD_ADD_IF_NOT_PRESENT: 1215 if ( attr_find( entry->e_attrs, mods->sm_desc ) ) { 1216 rc = LDAP_SUCCESS; 1217 break; 1218 } 1219 mods->sm_op = LDAP_MOD_ADD; 1220 rc = modify_add_values(entry, mods, 1221 get_permissiveModify(op), 1222 &rs->sr_text, textbuf, 1223 SLAP_TEXT_BUFLEN ); 1224 mods->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT; 1225 break; 1226 } 1227 if(rc != LDAP_SUCCESS) break; 1228 } 1229 1230 if ( rc == LDAP_SUCCESS ) { 1231 rs->sr_text = NULL; /* Needed at least with SLAP_MOD_SOFTADD */ 1232 if ( is_oc ) { 1233 entry->e_ocflags = 0; 1234 } 1235 /* check that the entry still obeys the schema */ 1236 rc = entry_schema_check( op, entry, NULL, 0, 0, NULL, 1237 &rs->sr_text, textbuf, SLAP_TEXT_BUFLEN ); 1238 } 1239 1240 return rc; 1241} 1242 1243 1244static int 1245ldif_back_referrals( Operation *op, SlapReply *rs ) 1246{ 1247 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private; 1248 struct berval path, dn = op->o_req_dn, ndn = op->o_req_ndn; 1249 ber_len_t min_dnlen; 1250 Entry *entry = NULL, **entryp; 1251 BerVarray ref; 1252 int rc; 1253 1254 min_dnlen = op->o_bd->be_nsuffix[0].bv_len; 1255 if ( min_dnlen == 0 ) { 1256 /* Catch root DSE (empty DN), it is not a referral */ 1257 min_dnlen = 1; 1258 } 1259 if ( ndn2path( op, &ndn, &path, 0 ) != LDAP_SUCCESS ) { 1260 return LDAP_SUCCESS; /* Root DSE again */ 1261 } 1262 1263 entryp = get_manageDSAit( op ) ? NULL : &entry; 1264 ldap_pvt_thread_rdwr_rlock( &li->li_rdwr ); 1265 1266 for (;;) { 1267 dnParent( &dn, &dn ); 1268 dnParent( &ndn, &ndn ); 1269 rc = ldif_read_entry( op, path.bv_val, &dn, &ndn, 1270 entryp, &rs->sr_text ); 1271 if ( rc != LDAP_NO_SUCH_OBJECT ) 1272 break; 1273 1274 rc = LDAP_SUCCESS; 1275 if ( ndn.bv_len < min_dnlen ) 1276 break; 1277 (void) get_parent_path( &path, NULL ); 1278 dir2ldif_name( path ); 1279 entryp = &entry; 1280 } 1281 1282 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr ); 1283 SLAP_FREE( path.bv_val ); 1284 1285 if ( entry != NULL ) { 1286 if ( is_entry_referral( entry ) ) { 1287 Debug( LDAP_DEBUG_TRACE, 1288 "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n", 1289 (unsigned long) op->o_tag, op->o_req_dn.bv_val, entry->e_dn ); 1290 1291 ref = get_entry_referrals( op, entry ); 1292 rs->sr_ref = referral_rewrite( ref, &entry->e_name, &op->o_req_dn, 1293 op->o_tag == LDAP_REQ_SEARCH ? 1294 op->ors_scope : LDAP_SCOPE_DEFAULT ); 1295 ber_bvarray_free( ref ); 1296 1297 if ( rs->sr_ref != NULL ) { 1298 /* send referral */ 1299 rc = rs->sr_err = LDAP_REFERRAL; 1300 rs->sr_matched = entry->e_dn; 1301 send_ldap_result( op, rs ); 1302 ber_bvarray_free( rs->sr_ref ); 1303 rs->sr_ref = NULL; 1304 } else { 1305 rc = LDAP_OTHER; 1306 rs->sr_text = "bad referral object"; 1307 } 1308 rs->sr_matched = NULL; 1309 } 1310 1311 entry_free( entry ); 1312 } 1313 1314 return rc; 1315} 1316 1317 1318/* LDAP operations */ 1319 1320static int 1321ldif_back_bind( Operation *op, SlapReply *rs ) 1322{ 1323 struct ldif_info *li; 1324 Attribute *a; 1325 AttributeDescription *password = slap_schema.si_ad_userPassword; 1326 int return_val; 1327 Entry *entry = NULL; 1328 1329 switch ( be_rootdn_bind( op, rs ) ) { 1330 case SLAP_CB_CONTINUE: 1331 break; 1332 1333 default: 1334 /* in case of success, front end will send result; 1335 * otherwise, be_rootdn_bind() did */ 1336 return rs->sr_err; 1337 } 1338 1339 li = (struct ldif_info *) op->o_bd->be_private; 1340 ldap_pvt_thread_rdwr_rlock(&li->li_rdwr); 1341 return_val = get_entry(op, &entry, NULL, NULL); 1342 1343 /* no object is found for them */ 1344 if(return_val != LDAP_SUCCESS) { 1345 rs->sr_err = return_val = LDAP_INVALID_CREDENTIALS; 1346 goto return_result; 1347 } 1348 1349 /* they don't have userpassword */ 1350 if((a = attr_find(entry->e_attrs, password)) == NULL) { 1351 rs->sr_err = LDAP_INAPPROPRIATE_AUTH; 1352 return_val = 1; 1353 goto return_result; 1354 } 1355 1356 /* authentication actually failed */ 1357 if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred, 1358 &rs->sr_text) != 0) { 1359 rs->sr_err = LDAP_INVALID_CREDENTIALS; 1360 return_val = 1; 1361 goto return_result; 1362 } 1363 1364 /* let the front-end send success */ 1365 return_val = LDAP_SUCCESS; 1366 1367 return_result: 1368 ldap_pvt_thread_rdwr_runlock(&li->li_rdwr); 1369 if(return_val != LDAP_SUCCESS) 1370 send_ldap_result( op, rs ); 1371 if(entry != NULL) 1372 entry_free(entry); 1373 return return_val; 1374} 1375 1376static int 1377ldif_back_search( Operation *op, SlapReply *rs ) 1378{ 1379 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private; 1380 1381 ldap_pvt_thread_rdwr_rlock(&li->li_rdwr); 1382 rs->sr_err = search_tree( op, rs ); 1383 ldap_pvt_thread_rdwr_runlock(&li->li_rdwr); 1384 send_ldap_result(op, rs); 1385 1386 return rs->sr_err; 1387} 1388 1389static int 1390ldif_back_add( Operation *op, SlapReply *rs ) 1391{ 1392 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private; 1393 Entry * e = op->ora_e; 1394 struct berval path; 1395 char *parentdir; 1396 char textbuf[SLAP_TEXT_BUFLEN]; 1397 int rc; 1398 1399 Debug( LDAP_DEBUG_TRACE, "ldif_back_add: \"%s\"\n", e->e_dn, 0, 0 ); 1400 1401 rc = entry_schema_check( op, e, NULL, 0, 1, NULL, 1402 &rs->sr_text, textbuf, sizeof( textbuf ) ); 1403 if ( rc != LDAP_SUCCESS ) 1404 goto send_res; 1405 1406 rc = slap_add_opattrs( op, &rs->sr_text, textbuf, sizeof( textbuf ), 1 ); 1407 if ( rc != LDAP_SUCCESS ) 1408 goto send_res; 1409 1410 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex ); 1411 1412 rc = ldif_prepare_create( op, e, &path, &parentdir, &rs->sr_text ); 1413 if ( rc == LDAP_SUCCESS ) { 1414 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr ); 1415 rc = ldif_write_entry( op, e, &path, parentdir, &rs->sr_text ); 1416 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr ); 1417 1418 SLAP_FREE( path.bv_val ); 1419 if ( parentdir != NULL ) 1420 SLAP_FREE( parentdir ); 1421 } 1422 1423 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex ); 1424 1425 send_res: 1426 rs->sr_err = rc; 1427 Debug( LDAP_DEBUG_TRACE, "ldif_back_add: err: %d text: %s\n", 1428 rc, rs->sr_text ? rs->sr_text : "", 0 ); 1429 send_ldap_result( op, rs ); 1430 slap_graduate_commit_csn( op ); 1431 rs->sr_text = NULL; /* remove possible pointer to textbuf */ 1432 return rs->sr_err; 1433} 1434 1435static int 1436ldif_back_modify( Operation *op, SlapReply *rs ) 1437{ 1438 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private; 1439 Modifications * modlst = op->orm_modlist; 1440 struct berval path; 1441 Entry *entry; 1442 char textbuf[SLAP_TEXT_BUFLEN]; 1443 int rc; 1444 1445 slap_mods_opattrs( op, &op->orm_modlist, 1 ); 1446 1447 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex ); 1448 1449 rc = get_entry( op, &entry, &path, &rs->sr_text ); 1450 if ( rc == LDAP_SUCCESS ) { 1451 rc = apply_modify_to_entry( entry, modlst, op, rs, textbuf ); 1452 if ( rc == LDAP_SUCCESS ) { 1453 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr ); 1454 rc = ldif_write_entry( op, entry, &path, NULL, &rs->sr_text ); 1455 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr ); 1456 } 1457 1458 entry_free( entry ); 1459 SLAP_FREE( path.bv_val ); 1460 } 1461 1462 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex ); 1463 1464 rs->sr_err = rc; 1465 send_ldap_result( op, rs ); 1466 slap_graduate_commit_csn( op ); 1467 rs->sr_text = NULL; /* remove possible pointer to textbuf */ 1468 return rs->sr_err; 1469} 1470 1471static int 1472ldif_back_delete( Operation *op, SlapReply *rs ) 1473{ 1474 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private; 1475 struct berval path; 1476 int rc = LDAP_SUCCESS; 1477 1478 if ( BER_BVISEMPTY( &op->o_csn )) { 1479 struct berval csn; 1480 char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE]; 1481 1482 csn.bv_val = csnbuf; 1483 csn.bv_len = sizeof( csnbuf ); 1484 slap_get_csn( op, &csn, 1 ); 1485 } 1486 1487 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex ); 1488 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr ); 1489 if ( op->o_abandon ) { 1490 rc = SLAPD_ABANDON; 1491 goto done; 1492 } 1493 1494 rc = ndn2path( op, &op->o_req_ndn, &path, 0 ); 1495 if ( rc != LDAP_SUCCESS ) { 1496 goto done; 1497 } 1498 1499 ldif2dir_len( path ); 1500 ldif2dir_name( path ); 1501 if ( rmdir( path.bv_val ) < 0 ) { 1502 switch ( errno ) { 1503 case ENOTEMPTY: 1504 rc = LDAP_NOT_ALLOWED_ON_NONLEAF; 1505 break; 1506 case ENOENT: 1507 /* is leaf, go on */ 1508 break; 1509 default: 1510 rc = LDAP_OTHER; 1511 rs->sr_text = "internal error (cannot delete subtree directory)"; 1512 break; 1513 } 1514 } 1515 1516 if ( rc == LDAP_SUCCESS ) { 1517 dir2ldif_name( path ); 1518 if ( unlink( path.bv_val ) < 0 ) { 1519 rc = LDAP_NO_SUCH_OBJECT; 1520 if ( errno != ENOENT ) { 1521 rc = LDAP_OTHER; 1522 rs->sr_text = "internal error (cannot delete entry file)"; 1523 } 1524 } 1525 } 1526 1527 if ( rc == LDAP_OTHER ) { 1528 Debug( LDAP_DEBUG_ANY, "ldif_back_delete: %s \"%s\": %s\n", 1529 "cannot delete", path.bv_val, STRERROR( errno ) ); 1530 } 1531 1532 SLAP_FREE( path.bv_val ); 1533 done: 1534 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr ); 1535 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex ); 1536 rs->sr_err = rc; 1537 send_ldap_result( op, rs ); 1538 slap_graduate_commit_csn( op ); 1539 return rs->sr_err; 1540} 1541 1542 1543static int 1544ldif_move_entry( 1545 Operation *op, 1546 Entry *entry, 1547 int same_ndn, 1548 struct berval *oldpath, 1549 const char **text ) 1550{ 1551 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private; 1552 struct berval newpath; 1553 char *parentdir = NULL, *trash; 1554 int rc, rename_res; 1555 1556 if ( same_ndn ) { 1557 rc = LDAP_SUCCESS; 1558 newpath = *oldpath; 1559 } else { 1560 rc = ldif_prepare_create( op, entry, &newpath, 1561 op->orr_newSup ? &parentdir : NULL, text ); 1562 } 1563 1564 if ( rc == LDAP_SUCCESS ) { 1565 ldap_pvt_thread_rdwr_wlock( &li->li_rdwr ); 1566 1567 rc = ldif_write_entry( op, entry, &newpath, parentdir, text ); 1568 if ( rc == LDAP_SUCCESS && !same_ndn ) { 1569 trash = oldpath->bv_val; /* will be .ldif file to delete */ 1570 ldif2dir_len( newpath ); 1571 ldif2dir_len( *oldpath ); 1572 /* Move subdir before deleting old entry, 1573 * so .ldif always exists if subdir does. 1574 */ 1575 ldif2dir_name( newpath ); 1576 ldif2dir_name( *oldpath ); 1577 rename_res = move_dir( oldpath->bv_val, newpath.bv_val ); 1578 if ( rename_res != 0 && errno != ENOENT ) { 1579 rc = LDAP_OTHER; 1580 *text = "internal error (cannot move this subtree)"; 1581 trash = newpath.bv_val; 1582 } 1583 1584 /* Delete old entry, or if error undo change */ 1585 for (;;) { 1586 dir2ldif_name( newpath ); 1587 dir2ldif_name( *oldpath ); 1588 if ( unlink( trash ) == 0 ) 1589 break; 1590 if ( rc == LDAP_SUCCESS ) { 1591 /* Prepare to undo change and return failure */ 1592 rc = LDAP_OTHER; 1593 *text = "internal error (cannot move this entry)"; 1594 trash = newpath.bv_val; 1595 if ( rename_res != 0 ) 1596 continue; 1597 /* First move subdirectory back */ 1598 ldif2dir_name( newpath ); 1599 ldif2dir_name( *oldpath ); 1600 if ( move_dir( newpath.bv_val, oldpath->bv_val ) == 0 ) 1601 continue; 1602 } 1603 *text = "added new but couldn't delete old entry!"; 1604 break; 1605 } 1606 1607 if ( rc != LDAP_SUCCESS ) { 1608 char s[128]; 1609 snprintf( s, sizeof s, "%s (%s)", *text, STRERROR( errno )); 1610 Debug( LDAP_DEBUG_ANY, 1611 "ldif_move_entry: %s: \"%s\" -> \"%s\"\n", 1612 s, op->o_req_dn.bv_val, entry->e_dn ); 1613 } 1614 } 1615 1616 ldap_pvt_thread_rdwr_wunlock( &li->li_rdwr ); 1617 if ( !same_ndn ) 1618 SLAP_FREE( newpath.bv_val ); 1619 if ( parentdir != NULL ) 1620 SLAP_FREE( parentdir ); 1621 } 1622 1623 return rc; 1624} 1625 1626static int 1627ldif_back_modrdn( Operation *op, SlapReply *rs ) 1628{ 1629 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private; 1630 struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL; 1631 struct berval p_dn, old_path; 1632 Entry *entry; 1633 char textbuf[SLAP_TEXT_BUFLEN]; 1634 int rc, same_ndn; 1635 1636 slap_mods_opattrs( op, &op->orr_modlist, 1 ); 1637 1638 ldap_pvt_thread_mutex_lock( &li->li_modop_mutex ); 1639 1640 rc = get_entry( op, &entry, &old_path, &rs->sr_text ); 1641 if ( rc == LDAP_SUCCESS ) { 1642 /* build new dn, and new ndn for the entry */ 1643 if ( op->oq_modrdn.rs_newSup != NULL ) { 1644 p_dn = *op->oq_modrdn.rs_newSup; 1645 } else { 1646 dnParent( &entry->e_name, &p_dn ); 1647 } 1648 build_new_dn( &new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL ); 1649 dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, NULL ); 1650 same_ndn = !ber_bvcmp( &entry->e_nname, &new_ndn ); 1651 ber_memfree_x( entry->e_name.bv_val, NULL ); 1652 ber_memfree_x( entry->e_nname.bv_val, NULL ); 1653 entry->e_name = new_dn; 1654 entry->e_nname = new_ndn; 1655 1656 /* perform the modifications */ 1657 rc = apply_modify_to_entry( entry, op->orr_modlist, op, rs, textbuf ); 1658 if ( rc == LDAP_SUCCESS ) 1659 rc = ldif_move_entry( op, entry, same_ndn, &old_path, 1660 &rs->sr_text ); 1661 1662 entry_free( entry ); 1663 SLAP_FREE( old_path.bv_val ); 1664 } 1665 1666 ldap_pvt_thread_mutex_unlock( &li->li_modop_mutex ); 1667 rs->sr_err = rc; 1668 send_ldap_result( op, rs ); 1669 slap_graduate_commit_csn( op ); 1670 rs->sr_text = NULL; /* remove possible pointer to textbuf */ 1671 return rs->sr_err; 1672} 1673 1674 1675/* Return LDAP_SUCCESS IFF we retrieve the specified entry. */ 1676static int 1677ldif_back_entry_get( 1678 Operation *op, 1679 struct berval *ndn, 1680 ObjectClass *oc, 1681 AttributeDescription *at, 1682 int rw, 1683 Entry **e ) 1684{ 1685 struct ldif_info *li = (struct ldif_info *) op->o_bd->be_private; 1686 struct berval op_dn = op->o_req_dn, op_ndn = op->o_req_ndn; 1687 int rc; 1688 1689 assert( ndn != NULL ); 1690 assert( !BER_BVISNULL( ndn ) ); 1691 1692 ldap_pvt_thread_rdwr_rlock( &li->li_rdwr ); 1693 op->o_req_dn = *ndn; 1694 op->o_req_ndn = *ndn; 1695 rc = get_entry( op, e, NULL, NULL ); 1696 op->o_req_dn = op_dn; 1697 op->o_req_ndn = op_ndn; 1698 ldap_pvt_thread_rdwr_runlock( &li->li_rdwr ); 1699 1700 if ( rc == LDAP_SUCCESS && oc && !is_entry_objectclass_or_sub( *e, oc ) ) { 1701 rc = LDAP_NO_SUCH_ATTRIBUTE; 1702 entry_free( *e ); 1703 *e = NULL; 1704 } 1705 1706 return rc; 1707} 1708 1709 1710/* Slap tools */ 1711 1712static int 1713ldif_tool_entry_open( BackendDB *be, int mode ) 1714{ 1715 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool; 1716 1717 tl->ecurrent = 0; 1718 return 0; 1719} 1720 1721static int 1722ldif_tool_entry_close( BackendDB *be ) 1723{ 1724 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool; 1725 Entry **entries = tl->entries; 1726 ID i; 1727 1728 for ( i = tl->ecount; i--; ) 1729 if ( entries[i] ) 1730 entry_free( entries[i] ); 1731 SLAP_FREE( entries ); 1732 tl->entries = NULL; 1733 tl->ecount = tl->elen = 0; 1734 return 0; 1735} 1736 1737static ID 1738ldif_tool_entry_next( BackendDB *be ) 1739{ 1740 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool; 1741 1742 do { 1743 Entry *e = tl->entries[ tl->ecurrent ]; 1744 1745 if ( tl->ecurrent >= tl->ecount ) { 1746 return NOID; 1747 } 1748 1749 ++tl->ecurrent; 1750 1751 if ( tl->tl_base && !dnIsSuffixScope( &e->e_nname, tl->tl_base, tl->tl_scope ) ) { 1752 continue; 1753 } 1754 1755 if ( tl->tl_filter && test_filter( NULL, e, tl->tl_filter ) != LDAP_COMPARE_TRUE ) { 1756 continue; 1757 } 1758 1759 break; 1760 } while ( 1 ); 1761 1762 return tl->ecurrent; 1763} 1764 1765static ID 1766ldif_tool_entry_first_x( BackendDB *be, struct berval *base, int scope, Filter *f ) 1767{ 1768 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool; 1769 1770 tl->tl_base = base; 1771 tl->tl_scope = scope; 1772 tl->tl_filter = f; 1773 1774 if ( tl->entries == NULL ) { 1775 Operation op = {0}; 1776 1777 op.o_bd = be; 1778 op.o_req_dn = *be->be_suffix; 1779 op.o_req_ndn = *be->be_nsuffix; 1780 op.ors_scope = LDAP_SCOPE_SUBTREE; 1781 if ( search_tree( &op, NULL ) != LDAP_SUCCESS ) { 1782 tl->ecurrent = tl->ecount; /* fail ldif_tool_entry_next() */ 1783 return 0; /* fail ldif_tool_entry_get() */ 1784 } 1785 } 1786 return ldif_tool_entry_next( be ); 1787} 1788 1789static Entry * 1790ldif_tool_entry_get( BackendDB *be, ID id ) 1791{ 1792 struct ldif_tool *tl = &((struct ldif_info *) be->be_private)->li_tool; 1793 Entry *e = NULL; 1794 1795 --id; 1796 if ( id < tl->ecount ) { 1797 e = tl->entries[id]; 1798 tl->entries[id] = NULL; 1799 } 1800 return e; 1801} 1802 1803static ID 1804ldif_tool_entry_put( BackendDB *be, Entry *e, struct berval *text ) 1805{ 1806 int rc; 1807 const char *errmsg = NULL; 1808 struct berval path; 1809 char *parentdir; 1810 Operation op = {0}; 1811 1812 op.o_bd = be; 1813 rc = ldif_prepare_create( &op, e, &path, &parentdir, &errmsg ); 1814 if ( rc == LDAP_SUCCESS ) { 1815 rc = ldif_write_entry( &op, e, &path, parentdir, &errmsg ); 1816 1817 SLAP_FREE( path.bv_val ); 1818 if ( parentdir != NULL ) 1819 SLAP_FREE( parentdir ); 1820 if ( rc == LDAP_SUCCESS ) 1821 return 1; 1822 } 1823 1824 if ( errmsg == NULL && rc != LDAP_OTHER ) 1825 errmsg = ldap_err2string( rc ); 1826 if ( errmsg != NULL ) 1827 snprintf( text->bv_val, text->bv_len, "%s", errmsg ); 1828 return NOID; 1829} 1830 1831 1832/* Setup */ 1833 1834static int 1835ldif_back_db_init( BackendDB *be, ConfigReply *cr ) 1836{ 1837 struct ldif_info *li; 1838 1839 li = ch_calloc( 1, sizeof(struct ldif_info) ); 1840 be->be_private = li; 1841 be->be_cf_ocs = ldifocs; 1842 ldap_pvt_thread_mutex_init( &li->li_modop_mutex ); 1843 ldap_pvt_thread_rdwr_init( &li->li_rdwr ); 1844 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_ONE_SUFFIX; 1845 return 0; 1846} 1847 1848static int 1849ldif_back_db_destroy( Backend *be, ConfigReply *cr ) 1850{ 1851 struct ldif_info *li = be->be_private; 1852 1853 ch_free( li->li_base_path.bv_val ); 1854 ldap_pvt_thread_rdwr_destroy( &li->li_rdwr ); 1855 ldap_pvt_thread_mutex_destroy( &li->li_modop_mutex ); 1856 free( be->be_private ); 1857 return 0; 1858} 1859 1860static int 1861ldif_back_db_open( Backend *be, ConfigReply *cr ) 1862{ 1863 struct ldif_info *li = (struct ldif_info *) be->be_private; 1864 if( BER_BVISEMPTY(&li->li_base_path)) {/* missing base path */ 1865 Debug( LDAP_DEBUG_ANY, "missing base path for back-ldif\n", 0, 0, 0); 1866 return 1; 1867 } 1868 return 0; 1869} 1870 1871int 1872ldif_back_initialize( BackendInfo *bi ) 1873{ 1874 static char *controls[] = { 1875 LDAP_CONTROL_MANAGEDSAIT, 1876 NULL 1877 }; 1878 int rc; 1879 1880 bi->bi_flags |= 1881 SLAP_BFLAG_INCREMENT | 1882 SLAP_BFLAG_REFERRALS; 1883 1884 bi->bi_controls = controls; 1885 1886 bi->bi_open = 0; 1887 bi->bi_close = 0; 1888 bi->bi_config = 0; 1889 bi->bi_destroy = 0; 1890 1891 bi->bi_db_init = ldif_back_db_init; 1892 bi->bi_db_config = config_generic_wrapper; 1893 bi->bi_db_open = ldif_back_db_open; 1894 bi->bi_db_close = 0; 1895 bi->bi_db_destroy = ldif_back_db_destroy; 1896 1897 bi->bi_op_bind = ldif_back_bind; 1898 bi->bi_op_unbind = 0; 1899 bi->bi_op_search = ldif_back_search; 1900 bi->bi_op_compare = 0; 1901 bi->bi_op_modify = ldif_back_modify; 1902 bi->bi_op_modrdn = ldif_back_modrdn; 1903 bi->bi_op_add = ldif_back_add; 1904 bi->bi_op_delete = ldif_back_delete; 1905 bi->bi_op_abandon = 0; 1906 1907 bi->bi_extended = 0; 1908 1909 bi->bi_chk_referrals = ldif_back_referrals; 1910 1911 bi->bi_connection_init = 0; 1912 bi->bi_connection_destroy = 0; 1913 1914 bi->bi_entry_get_rw = ldif_back_entry_get; 1915 1916#if 0 /* NOTE: uncomment to completely disable access control */ 1917 bi->bi_access_allowed = slap_access_always_allowed; 1918#endif 1919 1920 bi->bi_tool_entry_open = ldif_tool_entry_open; 1921 bi->bi_tool_entry_close = ldif_tool_entry_close; 1922 bi->bi_tool_entry_first = backend_tool_entry_first; 1923 bi->bi_tool_entry_first_x = ldif_tool_entry_first_x; 1924 bi->bi_tool_entry_next = ldif_tool_entry_next; 1925 bi->bi_tool_entry_get = ldif_tool_entry_get; 1926 bi->bi_tool_entry_put = ldif_tool_entry_put; 1927 bi->bi_tool_entry_reindex = 0; 1928 bi->bi_tool_sync = 0; 1929 1930 bi->bi_tool_dn2id_get = 0; 1931 bi->bi_tool_entry_modify = 0; 1932 1933 bi->bi_cf_ocs = ldifocs; 1934 1935 rc = config_register_schema( ldifcfg, ldifocs ); 1936 if ( rc ) return rc; 1937 return 0; 1938} 1939