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