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