1 /* ldif.c - the ldif backend */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/back-ldif/ldif.c,v 1.48.2.14 2008/04/21 18:53:52 quanah Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2005-2008 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
17 * This work was originally developed by Eric Stokes for inclusion
18 * in OpenLDAP Software.
23 #include <ac/string.h>
24 #include <sys/types.h>
26 #include <ac/dirent.h>
29 #include <ac/unistd.h>
34 typedef struct enumCookie
{
43 struct berval li_base_path
;
44 enumCookie li_tool_cookie
;
46 ldap_pvt_thread_rdwr_t li_rdwr
;
50 #define mkdir(a,b) mkdir(a)
55 #define LDIF_FILETYPE_SEP '.' /* LDIF[0] */
58 * Unsafe/translated characters in the filesystem.
60 * LDIF_UNSAFE_CHAR(c) returns true if the character c is not to be used
61 * in relative filenames, except it should accept '\\' even if unsafe and
62 * need not reject '{' and '}'. The value should be a constant expression.
64 * If '\\' is unsafe, #define LDIF_ESCAPE_CHAR as a safe character.
66 * If '{' and '}' are unsafe, #define IX_FSL/IX_FSR as safe characters.
67 * (Not digits, '-' or '+'. IX_FSL == IX_FSR is allowed.)
69 * Characters are escaped as LDIF_ESCAPE_CHAR followed by two hex digits,
70 * except '\\' is replaced with LDIF_ESCAPE_CHAR and {} with IX_FS[LR].
71 * Also some LDIF special chars are hex-escaped.
73 * Thus an LDIF filename is a valid normalized RDN (or suffix DN)
74 * followed by ".ldif", except with '\\' replaced with LDIF_ESCAPE_CHAR.
80 * Unix/MacOSX version. ':' vs '/' can cause confusion on MacOSX so we
81 * escape both. We escape them on Unix so both OS variants get the same
84 #define LDIF_ESCAPE_CHAR '\\'
85 #define LDIF_UNSAFE_CHAR(c) ((c) == '/' || (c) == ':')
89 /* Windows version - Microsoft's list of unsafe characters, except '\\' */
90 #define LDIF_ESCAPE_CHAR '^'
91 #define LDIF_UNSAFE_CHAR(c) \
92 ((c) == '/' || (c) == ':' || \
93 (c) == '<' || (c) == '>' || (c) == '"' || \
94 (c) == '|' || (c) == '?' || (c) == '*')
99 * Left and Right "{num}" prefix to ordered RDNs ("olcDatabase={1}bdb").
100 * IX_DN* are for LDAP RDNs, IX_FS* for their .ldif filenames.
105 #define IX_FSL IX_DNL
106 #define IX_FSR IX_DNR
110 * Test for unsafe chars, as well as chars handled specially by back-ldif:
111 * - If the escape char is not '\\', it must itself be escaped. Otherwise
112 * '\\' and the escape char would map to the same character.
113 * - Escape the '.' in ".ldif", so the directory for an RDN that actually
114 * ends with ".ldif" can not conflict with a file of the same name. And
115 * since some OSes/programs choke on multiple '.'s, escape all of them.
116 * - If '{' and '}' are translated to some other characters, those
117 * characters must in turn be escaped when they occur in an RDN.
119 #ifndef LDIF_NEED_ESCAPE
120 #define LDIF_NEED_ESCAPE(c) \
121 ((LDIF_UNSAFE_CHAR(c)) || \
122 LDIF_MAYBE_UNSAFE(c, LDIF_ESCAPE_CHAR) || \
123 LDIF_MAYBE_UNSAFE(c, LDIF_FILETYPE_SEP) || \
124 LDIF_MAYBE_UNSAFE(c, IX_FSL) || \
125 (IX_FSR != IX_FSL && LDIF_MAYBE_UNSAFE(c, IX_FSR)))
128 * Helper macro for LDIF_NEED_ESCAPE(): Treat character x as unsafe if
129 * back-ldif does not already treat is specially.
131 #define LDIF_MAYBE_UNSAFE(c, x) \
132 (!(LDIF_UNSAFE_CHAR(x) || (x) == '\\' || (x) == IX_DNL || (x) == IX_DNR) \
136 #define ENTRY_BUFF_INCREMENT 500
138 static ConfigTable ldifcfg
[] = {
139 { "directory", "dir", 2, 2, 0, ARG_BERVAL
|ARG_OFFSET
,
140 (void *)offsetof(struct ldif_info
, li_base_path
),
141 "( OLcfgDbAt:0.1 NAME 'olcDbDirectory' "
142 "DESC 'Directory for database content' "
143 "EQUALITY caseIgnoreMatch "
144 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL
, NULL
},
145 { NULL
, NULL
, 0, 0, 0, ARG_IGNORED
,
146 NULL
, NULL
, NULL
, NULL
}
149 static ConfigOCs ldifocs
[] = {
151 "NAME 'olcLdifConfig' "
152 "DESC 'LDIF backend configuration' "
153 "SUP olcDatabaseConfig "
154 "MUST ( olcDbDirectory ) )", Cft_Database
, ldifcfg
},
159 /* Set *res = LDIF filename path for the normalized DN */
161 dn2path( BackendDB
*be
, struct berval
*dn
, struct berval
*res
)
163 struct ldif_info
*li
= (struct ldif_info
*) be
->be_private
;
164 struct berval
*suffixdn
= &be
->be_nsuffix
[0];
165 const char *start
, *end
, *next
, *p
;
168 static const char hex
[] = "0123456789ABCDEF";
170 assert( dn
!= NULL
);
171 assert( !BER_BVISNULL( dn
) );
172 assert( suffixdn
!= NULL
);
173 assert( !BER_BVISNULL( suffixdn
) );
174 assert( dnIsSuffix( dn
, suffixdn
) );
177 end
= start
+ dn
->bv_len
;
179 /* Room for dir, dirsep, dn, LDIF, "\hexpair"-escaping of unsafe chars */
180 len
= li
->li_base_path
.bv_len
+ dn
->bv_len
+ (1 + STRLENOF( LDIF
));
181 for ( p
= start
; p
< end
; ) {
183 if ( LDIF_NEED_ESCAPE( ch
) )
186 res
->bv_val
= ch_malloc( len
+ 1 );
188 ptr
= lutil_strcopy( res
->bv_val
, li
->li_base_path
.bv_val
);
189 for ( next
= end
- suffixdn
->bv_len
; end
> start
; end
= next
) {
190 /* Set p = start of DN component, next = &',' or start of DN */
191 while ( (p
= next
) > start
) {
193 if ( DN_SEPARATOR( *next
) )
196 /* Append <dirsep> <p..end-1: RDN or database-suffix> */
197 for ( *ptr
++ = LDAP_DIRSEP
[0]; p
< end
; *ptr
++ = ch
) {
199 if ( LDIF_ESCAPE_CHAR
!= '\\' && ch
== '\\' ) {
200 ch
= LDIF_ESCAPE_CHAR
;
201 } else if ( IX_FSL
!= IX_DNL
&& ch
== IX_DNL
) {
203 } else if ( IX_FSR
!= IX_DNR
&& ch
== IX_DNR
) {
205 } else if ( LDIF_NEED_ESCAPE( ch
) ) {
206 *ptr
++ = LDIF_ESCAPE_CHAR
;
207 *ptr
++ = hex
[(ch
& 0xFFU
) >> 4];
208 ch
= hex
[ch
& 0x0FU
];
212 ptr
= lutil_strcopy( ptr
, LDIF
);
213 res
->bv_len
= ptr
- res
->bv_val
;
215 assert( res
->bv_len
<= len
);
218 static char * slurp_file(int fd
) {
219 int read_chars_total
= 0;
227 entry_size
= st
.st_size
;
228 entry
= ch_malloc( entry_size
+1 );
232 read_chars
= read(fd
, (void *) entry_pos
, entry_size
- read_chars_total
);
233 if(read_chars
== -1) {
237 if(read_chars
== 0) {
238 entry
[read_chars_total
] = '\0';
242 read_chars_total
+= read_chars
;
243 entry_pos
+= read_chars
;
250 * return nonnegative for success or -1 for error
251 * do not return numbers less than -1
253 static int spew_file(int fd
, char * spew
, int len
) {
257 writeres
= write(fd
, spew
, len
);
270 spew_entry( Entry
* e
, struct berval
* path
, int dolock
, int *save_errnop
)
272 int rs
, save_errno
= 0;
276 char * entry_as_string
;
277 char *tmpfname
= NULL
;
279 tmpfname
= ch_malloc( path
->bv_len
+ STRLENOF( "XXXXXX" ) + 1 );
280 AC_MEMCPY( tmpfname
, path
->bv_val
, path
->bv_len
);
281 AC_MEMCPY( &tmpfname
[ path
->bv_len
], "XXXXXX", STRLENOF( "XXXXXX" ) + 1 );
283 openres
= mkstemp( tmpfname
);
284 if ( openres
== -1 ) {
286 rs
= LDAP_UNWILLING_TO_PERFORM
;
287 Debug( LDAP_DEBUG_ANY
, "could not create tmpfile \"%s\": %s\n",
288 tmpfname
, STRERROR( save_errno
), 0 );
294 /* Only save the RDN onto disk */
295 dnRdn( &e
->e_name
, &rdn
);
296 if ( rdn
.bv_len
!= e
->e_name
.bv_len
) {
297 e
->e_name
.bv_val
[rdn
.bv_len
] = '\0';
298 tmp
= e
->e_name
.bv_len
;
299 e
->e_name
.bv_len
= rdn
.bv_len
;
305 ldap_pvt_thread_mutex_lock(&entry2str_mutex
);
308 entry_as_string
= entry2str(e
, &entry_length
);
309 if ( entry_as_string
!= NULL
) {
310 spew_res
= spew_file( openres
,
311 entry_as_string
, entry_length
);
312 if ( spew_res
== -1 ) {
318 ldap_pvt_thread_mutex_unlock(&entry2str_mutex
);
321 /* Restore full DN */
322 if ( rdn
.bv_len
!= e
->e_name
.bv_len
) {
323 e
->e_name
.bv_val
[e
->e_name
.bv_len
] = ',';
324 e
->e_name
.bv_len
= rdn
.bv_len
;
327 res
= close( openres
);
328 rs
= LDAP_UNWILLING_TO_PERFORM
;
330 if ( spew_res
> -2 ) {
331 if ( res
== -1 || spew_res
== -1 ) {
332 if ( save_errno
== 0 ) {
335 Debug( LDAP_DEBUG_ANY
, "write error to tmpfile \"%s\": %s\n",
336 tmpfname
, STRERROR( save_errno
), 0 );
339 res
= rename( tmpfname
, path
->bv_val
);
345 switch ( save_errno
) {
347 rs
= LDAP_NO_SUCH_OBJECT
;
357 if ( rs
!= LDAP_SUCCESS
) {
364 if ( rs
!= LDAP_SUCCESS
&& save_errnop
!= NULL
) {
365 *save_errnop
= save_errno
;
371 static Entry
* get_entry_for_fd(int fd
,
375 char * entry
= (char *) slurp_file(fd
);
376 Entry
* ldentry
= NULL
;
378 /* error reading file */
383 ldentry
= str2entry(entry
);
386 rdn
= ldentry
->e_name
;
387 build_new_dn( &ldentry
->e_name
, pdn
, &rdn
, NULL
);
388 ch_free( rdn
.bv_val
);
389 rdn
= ldentry
->e_nname
;
390 build_new_dn( &ldentry
->e_nname
, pndn
, &rdn
, NULL
);
391 ch_free( rdn
.bv_val
);
409 struct berval
*pathp
)
412 struct berval path
, pdn
, pndn
;
415 dnParent(&op
->o_req_dn
, &pdn
);
416 dnParent(&op
->o_req_ndn
, &pndn
);
417 dn2path( op
->o_bd
, &op
->o_req_ndn
, &path
);
418 fd
= open(path
.bv_val
, O_RDONLY
);
419 /* error opening file (mebbe should log error) */
420 if ( fd
== -1 && ( errno
!= ENOENT
|| op
->o_tag
!= LDAP_REQ_ADD
) ) {
421 Debug( LDAP_DEBUG_ANY
, "failed to open file \"%s\": %s\n",
422 path
.bv_val
, STRERROR(errno
), 0 );
424 *entryp
= fd
< 0 ? NULL
: get_entry_for_fd( fd
, &pdn
, &pndn
);
425 rc
= *entryp
? LDAP_SUCCESS
: LDAP_NO_SUCH_OBJECT
;
427 if ( rc
== LDAP_SUCCESS
&& pathp
!= NULL
) {
430 SLAP_FREE(path
.bv_val
);
435 static void fullpath(struct berval
*base
, struct berval
*name
, struct berval
*res
) {
437 res
->bv_len
= name
->bv_len
+ base
->bv_len
+ 1;
438 res
->bv_val
= ch_malloc( res
->bv_len
+ 1 );
439 strcpy(res
->bv_val
, base
->bv_val
);
440 ptr
= res
->bv_val
+ base
->bv_len
;
441 *ptr
++ = LDAP_DIRSEP
[0];
442 strcpy(ptr
, name
->bv_val
);
445 typedef struct bvlist
{
454 static int r_enum_tree(enumCookie
*ck
, struct berval
*path
, int base
,
455 struct berval
*pdn
, struct berval
*pndn
)
458 int fd
= 0, rc
= LDAP_SUCCESS
;
461 fd
= open( path
->bv_val
, O_RDONLY
);
463 Debug( LDAP_DEBUG_TRACE
,
464 "=> ldif_enum_tree: failed to open %s: %s\n",
465 path
->bv_val
, STRERROR(errno
), 0 );
466 return LDAP_NO_SUCH_OBJECT
;
469 e
= get_entry_for_fd(fd
, pdn
, pndn
);
471 Debug( LDAP_DEBUG_ANY
,
472 "=> ldif_enum_tree: failed to read entry for %s\n",
473 path
->bv_val
, 0, 0 );
477 if ( ck
->op
->ors_scope
== LDAP_SCOPE_BASE
||
478 ck
->op
->ors_scope
== LDAP_SCOPE_SUBTREE
) {
479 /* Send right away? */
482 * if it's a referral, add it to the list of referrals. only do
483 * this for non-base searches, and don't check the filter
484 * explicitly here since it's only a candidate anyway.
486 if ( !get_manageDSAit( ck
->op
)
487 && ck
->op
->ors_scope
!= LDAP_SCOPE_BASE
488 && is_entry_referral( e
) )
490 BerVarray erefs
= get_entry_referrals( ck
->op
, e
);
491 ck
->rs
->sr_ref
= referral_rewrite( erefs
,
493 ck
->op
->oq_search
.rs_scope
== LDAP_SCOPE_ONELEVEL
494 ? LDAP_SCOPE_BASE
: LDAP_SCOPE_SUBTREE
);
496 ck
->rs
->sr_entry
= e
;
497 rc
= send_search_reference( ck
->op
, ck
->rs
);
498 ber_bvarray_free( ck
->rs
->sr_ref
);
499 ber_bvarray_free( erefs
);
500 ck
->rs
->sr_ref
= NULL
;
501 ck
->rs
->sr_entry
= NULL
;
503 } else if ( test_filter( ck
->op
, e
, ck
->op
->ors_filter
) == LDAP_COMPARE_TRUE
)
505 ck
->rs
->sr_entry
= e
;
506 ck
->rs
->sr_attrs
= ck
->op
->ors_attrs
;
507 ck
->rs
->sr_flags
= REP_ENTRY_MODIFIABLE
;
508 rc
= send_search_entry(ck
->op
, ck
->rs
);
509 ck
->rs
->sr_entry
= NULL
;
515 /* Queueing up for tool mode */
516 if(ck
->entries
== NULL
) {
517 ck
->entries
= (Entry
**) ch_malloc(sizeof(Entry
*) * ENTRY_BUFF_INCREMENT
);
518 ck
->elen
= ENTRY_BUFF_INCREMENT
;
520 if(ck
->eind
>= ck
->elen
) { /* grow entries if necessary */
521 ck
->entries
= (Entry
**) ch_realloc(ck
->entries
, sizeof(Entry
*) * (ck
->elen
) * 2);
525 ck
->entries
[ck
->eind
++] = e
;
533 if ( ck
->op
->ors_scope
!= LDAP_SCOPE_BASE
) {
535 bvlist
*list
= NULL
, *ptr
;
537 path
->bv_len
-= STRLENOF( LDIF
);
538 path
->bv_val
[path
->bv_len
] = '\0';
540 dir_of_path
= opendir(path
->bv_val
);
541 if(dir_of_path
== NULL
) { /* can't open directory */
542 if ( errno
!= ENOENT
) {
543 /* it shouldn't be treated as an error
544 * only if the directory doesn't exist */
546 Debug( LDAP_DEBUG_ANY
,
547 "=> ldif_enum_tree: failed to opendir %s (%d)\n",
548 path
->bv_val
, errno
, 0 );
554 struct berval fname
, itmp
;
558 dir
= readdir(dir_of_path
);
559 if(dir
== NULL
) break; /* end of the directory */
560 fname
.bv_len
= strlen( dir
->d_name
);
561 if ( fname
.bv_len
<= STRLENOF( LDIF
))
563 if ( strcmp( dir
->d_name
+ (fname
.bv_len
- STRLENOF(LDIF
)), LDIF
))
565 fname
.bv_val
= dir
->d_name
;
567 bvl
= ch_malloc( sizeof(bvlist
) );
568 ber_dupbv( &bvl
->bv
, &fname
);
569 BER_BVZERO( &bvl
->num
);
570 itmp
.bv_val
= ber_bvchr( &bvl
->bv
, IX_FSL
);
574 itmp
.bv_len
= bvl
->bv
.bv_len
575 - ( itmp
.bv_val
- bvl
->bv
.bv_val
);
576 ptr
= ber_bvchr( &itmp
, IX_FSR
);
578 itmp
.bv_len
= ptr
- itmp
.bv_val
;
579 ber_dupbv( &bvl
->num
, &itmp
);
580 bvl
->inum
= strtol( itmp
.bv_val
, NULL
, 0 );
581 itmp
.bv_val
[0] = '\0';
582 bvl
->off
= itmp
.bv_val
- bvl
->bv
.bv_val
;
586 for (prev
= &list
; (ptr
= *prev
) != NULL
; prev
= &ptr
->next
) {
587 int cmp
= strcmp( bvl
->bv
.bv_val
, ptr
->bv
.bv_val
);
588 if ( !cmp
&& bvl
->num
.bv_val
)
589 cmp
= bvl
->inum
- ptr
->inum
;
597 closedir(dir_of_path
);
599 if (ck
->op
->ors_scope
== LDAP_SCOPE_ONELEVEL
)
600 ck
->op
->ors_scope
= LDAP_SCOPE_BASE
;
601 else if ( ck
->op
->ors_scope
== LDAP_SCOPE_SUBORDINATE
)
602 ck
->op
->ors_scope
= LDAP_SCOPE_SUBTREE
;
604 while ( ( ptr
= list
) ) {
609 if ( rc
== LDAP_SUCCESS
) {
610 if ( ptr
->num
.bv_val
)
611 AC_MEMCPY( ptr
->bv
.bv_val
+ ptr
->off
, ptr
->num
.bv_val
,
613 fullpath( path
, &ptr
->bv
, &fpath
);
614 rc
= r_enum_tree(ck
, &fpath
, 0,
615 e
!= NULL
? &e
->e_name
: pdn
,
616 e
!= NULL
? &e
->e_nname
: pndn
);
619 if ( ptr
->num
.bv_val
)
620 free( ptr
->num
.bv_val
);
621 free(ptr
->bv
.bv_val
);
626 if ( fd
) entry_free( e
);
636 struct berval pdn
, pndn
;
639 dnParent( &ck
->op
->o_req_dn
, &pdn
);
640 dnParent( &ck
->op
->o_req_ndn
, &pndn
);
641 dn2path( ck
->op
->o_bd
, &ck
->op
->o_req_ndn
, &path
);
642 rc
= r_enum_tree(ck
, &path
, BER_BVISEMPTY( &ck
->op
->o_req_ndn
) ? 1 : 0, &pdn
, &pndn
);
643 ch_free( path
.bv_val
);
648 /* Get the parent directory path, plus the LDIF suffix overwritten by a \0 */
650 get_parent_path( struct berval
*dnpath
, struct berval
*res
)
652 int dnpathlen
= dnpath
->bv_len
;
655 for(i
= dnpathlen
;i
>0;i
--) /* find the first path seperator */
656 if(dnpath
->bv_val
[i
] == LDAP_DIRSEP
[0])
659 res
->bv_val
= ch_malloc( res
->bv_len
+ 1 + STRLENOF(LDIF
) );
660 strncpy(res
->bv_val
, dnpath
->bv_val
, i
);
661 strcpy(res
->bv_val
+i
, LDIF
);
662 res
->bv_val
[i
] = '\0';
665 static int apply_modify_to_entry(Entry
* entry
,
666 Modifications
* modlist
,
670 char textbuf
[SLAP_TEXT_BUFLEN
];
671 int rc
= modlist
? LDAP_UNWILLING_TO_PERFORM
: LDAP_SUCCESS
;
675 if (!acl_check_modlist(op
, entry
, modlist
)) {
676 return LDAP_INSUFFICIENT_ACCESS
;
679 for (; modlist
!= NULL
; modlist
= modlist
->sml_next
) {
680 mods
= &modlist
->sml_mod
;
682 if ( mods
->sm_desc
== slap_schema
.si_ad_objectClass
) {
685 switch (mods
->sm_op
) {
687 rc
= modify_add_values(entry
, mods
,
688 get_permissiveModify(op
),
689 &rs
->sr_text
, textbuf
,
693 case LDAP_MOD_DELETE
:
694 rc
= modify_delete_values(entry
, mods
,
695 get_permissiveModify(op
),
696 &rs
->sr_text
, textbuf
,
700 case LDAP_MOD_REPLACE
:
701 rc
= modify_replace_values(entry
, mods
,
702 get_permissiveModify(op
),
703 &rs
->sr_text
, textbuf
,
707 case LDAP_MOD_INCREMENT
:
708 rc
= modify_increment_values( entry
,
709 mods
, get_permissiveModify(op
),
710 &rs
->sr_text
, textbuf
,
714 case SLAP_MOD_SOFTADD
:
715 mods
->sm_op
= LDAP_MOD_ADD
;
716 rc
= modify_add_values(entry
, mods
,
717 get_permissiveModify(op
),
718 &rs
->sr_text
, textbuf
,
720 mods
->sm_op
= SLAP_MOD_SOFTADD
;
721 if (rc
== LDAP_TYPE_OR_VALUE_EXISTS
) {
726 if(rc
!= LDAP_SUCCESS
) break;
729 if(rc
== LDAP_SUCCESS
) {
731 entry
->e_ocflags
= 0;
733 /* check that the entry still obeys the schema */
734 rc
= entry_schema_check( op
, entry
, NULL
, 0, 0,
735 &rs
->sr_text
, textbuf
, sizeof( textbuf
) );
742 ldif_back_referrals( Operation
*op
, SlapReply
*rs
)
744 struct ldif_info
*li
= NULL
;
746 int rc
= LDAP_SUCCESS
;
749 if ( op
->o_tag
== LDAP_REQ_SEARCH
) {
750 /* let search take care of itself */
755 if ( get_manageDSAit( op
) ) {
756 /* let op take care of DSA management */
760 if ( BER_BVISEMPTY( &op
->o_req_ndn
) ) {
761 /* the empty DN cannot be a referral */
765 li
= (struct ldif_info
*)op
->o_bd
->be_private
;
766 ldap_pvt_thread_rdwr_rlock( &li
->li_rdwr
);
767 get_entry( op
, &entry
, NULL
);
769 /* no object is found for them */
770 if ( entry
== NULL
) {
771 struct berval odn
= op
->o_req_dn
;
772 struct berval ondn
= op
->o_req_ndn
;
773 struct berval pndn
= ondn
;
774 ber_len_t min_dnlen
= op
->o_bd
->be_nsuffix
[0].bv_len
;
776 if ( min_dnlen
== 0 )
777 min_dnlen
= 1; /* catch empty DN */
779 for ( ; entry
== NULL
; ) {
780 dnParent( &pndn
, &pndn
);
781 if ( pndn
.bv_len
< min_dnlen
) {
786 op
->o_req_ndn
= pndn
;
788 get_entry( op
, &entry
, NULL
);
791 ldap_pvt_thread_rdwr_runlock( &li
->li_rdwr
);
794 op
->o_req_ndn
= ondn
;
797 rs
->sr_matched
= NULL
;
798 if ( entry
!= NULL
) {
799 Debug( LDAP_DEBUG_TRACE
,
800 "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n",
801 (unsigned long) op
->o_tag
, op
->o_req_dn
.bv_val
, entry
->e_name
.bv_val
);
803 if ( is_entry_referral( entry
) ) {
805 rs
->sr_ref
= get_entry_referrals( op
, entry
);
807 rs
->sr_matched
= ber_strdup_x(
808 entry
->e_name
.bv_val
, op
->o_tmpmemctx
);
814 } else if ( default_referral
!= NULL
) {
816 rs
->sr_ref
= referral_rewrite( default_referral
,
817 NULL
, &op
->o_req_dn
, LDAP_SCOPE_DEFAULT
);
820 if ( rs
->sr_ref
!= NULL
) {
822 rc
= rs
->sr_err
= LDAP_REFERRAL
;
823 send_ldap_result( op
, rs
);
824 ber_bvarray_free( rs
->sr_ref
);
827 } else if ( rc
!= LDAP_SUCCESS
) {
828 rs
->sr_text
= rs
->sr_matched
? "bad referral object" : NULL
;
831 if ( rs
->sr_matched
) {
832 op
->o_tmpfree( (char *)rs
->sr_matched
, op
->o_tmpmemctx
);
833 rs
->sr_matched
= NULL
;
839 ldap_pvt_thread_rdwr_runlock( &li
->li_rdwr
);
841 if ( is_entry_referral( entry
) ) {
842 /* entry is a referral */
843 BerVarray refs
= get_entry_referrals( op
, entry
);
844 rs
->sr_ref
= referral_rewrite(
845 refs
, &entry
->e_name
, &op
->o_req_dn
, LDAP_SCOPE_DEFAULT
);
847 Debug( LDAP_DEBUG_TRACE
,
848 "ldif_back_referrals: tag=%lu target=\"%s\" matched=\"%s\"\n",
849 (unsigned long) op
->o_tag
, op
->o_req_dn
.bv_val
, entry
->e_name
.bv_val
);
851 rs
->sr_matched
= entry
->e_name
.bv_val
;
852 if ( rs
->sr_ref
!= NULL
) {
853 rc
= rs
->sr_err
= LDAP_REFERRAL
;
854 send_ldap_result( op
, rs
);
855 ber_bvarray_free( rs
->sr_ref
);
860 rs
->sr_text
= "bad referral object";
863 rs
->sr_matched
= NULL
;
864 ber_bvarray_free( refs
);
873 /* LDAP operations */
876 ldif_back_bind( Operation
*op
, SlapReply
*rs
)
878 struct ldif_info
*li
;
880 AttributeDescription
*password
= slap_schema
.si_ad_userPassword
;
884 switch ( be_rootdn_bind( op
, rs
) ) {
885 case SLAP_CB_CONTINUE
:
889 /* in case of success, front end will send result;
890 * otherwise, be_rootdn_bind() did */
894 li
= (struct ldif_info
*) op
->o_bd
->be_private
;
895 ldap_pvt_thread_rdwr_rlock(&li
->li_rdwr
);
896 return_val
= get_entry(op
, &entry
, NULL
);
898 /* no object is found for them */
899 if(return_val
!= LDAP_SUCCESS
) {
900 rs
->sr_err
= return_val
= LDAP_INVALID_CREDENTIALS
;
904 /* they don't have userpassword */
905 if((a
= attr_find(entry
->e_attrs
, password
)) == NULL
) {
906 rs
->sr_err
= LDAP_INAPPROPRIATE_AUTH
;
911 /* authentication actually failed */
912 if(slap_passwd_check(op
, entry
, a
, &op
->oq_bind
.rb_cred
,
913 &rs
->sr_text
) != 0) {
914 rs
->sr_err
= LDAP_INVALID_CREDENTIALS
;
919 /* let the front-end send success */
924 ldap_pvt_thread_rdwr_runlock(&li
->li_rdwr
);
926 send_ldap_result( op
, rs
);
932 static int ldif_back_search(Operation
*op
, SlapReply
*rs
)
934 struct ldif_info
*li
= (struct ldif_info
*) op
->o_bd
->be_private
;
935 enumCookie ck
= { NULL
, NULL
, NULL
, 0, 0 };
939 ldap_pvt_thread_rdwr_rlock(&li
->li_rdwr
);
940 rs
->sr_err
= enum_tree( &ck
);
941 ldap_pvt_thread_rdwr_runlock(&li
->li_rdwr
);
942 send_ldap_result(op
, rs
);
947 static int ldif_back_add(Operation
*op
, SlapReply
*rs
) {
948 struct ldif_info
*li
= (struct ldif_info
*) op
->o_bd
->be_private
;
949 Entry
* e
= op
->ora_e
;
950 struct berval dn
= e
->e_nname
;
951 struct berval leaf_path
= BER_BVNULL
;
954 char textbuf
[SLAP_TEXT_BUFLEN
];
956 Debug( LDAP_DEBUG_TRACE
, "ldif_back_add: \"%s\"\n", dn
.bv_val
, 0, 0);
958 rs
->sr_err
= entry_schema_check(op
, e
, NULL
, 0, 1,
959 &rs
->sr_text
, textbuf
, sizeof( textbuf
) );
960 if ( rs
->sr_err
!= LDAP_SUCCESS
) goto send_res
;
962 rs
->sr_err
= slap_add_opattrs( op
,
963 &rs
->sr_text
, textbuf
, sizeof( textbuf
), 1 );
964 if ( rs
->sr_err
!= LDAP_SUCCESS
) goto send_res
;
966 ldap_pvt_thread_rdwr_wlock(&li
->li_rdwr
);
968 dn2path( op
->o_bd
, &dn
, &leaf_path
);
970 if(leaf_path
.bv_val
!= NULL
) {
971 struct berval base
= BER_BVNULL
;
972 /* build path to container and ldif of container */
973 get_parent_path(&leaf_path
, &base
);
975 statres
= stat(base
.bv_val
, &stats
); /* check if container exists */
976 if(statres
== -1 && errno
== ENOENT
) { /* container missing */
977 base
.bv_val
[base
.bv_len
] = LDIF_FILETYPE_SEP
;
978 statres
= stat(base
.bv_val
, &stats
); /* check for leaf node */
979 base
.bv_val
[base
.bv_len
] = '\0';
980 if(statres
== -1 && errno
== ENOENT
) {
981 rs
->sr_err
= LDAP_NO_SUCH_OBJECT
; /* parent doesn't exist */
982 rs
->sr_text
= "Parent does not exist";
984 else if(statres
!= -1) { /* create parent */
985 int mkdirres
= mkdir(base
.bv_val
, 0750);
987 rs
->sr_err
= LDAP_UNWILLING_TO_PERFORM
;
988 rs
->sr_text
= "Could not create parent folder";
989 Debug( LDAP_DEBUG_ANY
, "could not create folder \"%s\": %s\n",
990 base
.bv_val
, STRERROR( errno
), 0 );
994 rs
->sr_err
= LDAP_UNWILLING_TO_PERFORM
;
995 }/* container was possibly created, move on to add the entry */
996 if(rs
->sr_err
== LDAP_SUCCESS
) {
997 statres
= stat(leaf_path
.bv_val
, &stats
);
998 if(statres
== -1 && errno
== ENOENT
) {
999 rs
->sr_err
= spew_entry(e
, &leaf_path
, 1, NULL
);
1001 else if ( statres
== -1 ) {
1002 rs
->sr_err
= LDAP_UNWILLING_TO_PERFORM
;
1003 Debug( LDAP_DEBUG_ANY
, "could not stat file \"%s\": %s\n",
1004 leaf_path
.bv_val
, STRERROR( errno
), 0 );
1006 else /* it already exists */
1007 rs
->sr_err
= LDAP_ALREADY_EXISTS
;
1009 SLAP_FREE(base
.bv_val
);
1010 SLAP_FREE(leaf_path
.bv_val
);
1013 ldap_pvt_thread_rdwr_wunlock(&li
->li_rdwr
);
1016 Debug( LDAP_DEBUG_TRACE
,
1017 "ldif_back_add: err: %d text: %s\n", rs
->sr_err
, rs
->sr_text
?
1018 rs
->sr_text
: "", 0);
1019 send_ldap_result(op
, rs
);
1020 slap_graduate_commit_csn( op
);
1024 static int ldif_back_modify(Operation
*op
, SlapReply
*rs
) {
1025 struct ldif_info
*li
= (struct ldif_info
*) op
->o_bd
->be_private
;
1026 Modifications
* modlst
= op
->orm_modlist
;
1031 slap_mods_opattrs( op
, &op
->orm_modlist
, 1 );
1033 ldap_pvt_thread_rdwr_wlock(&li
->li_rdwr
);
1035 rs
->sr_err
= get_entry( op
, &entry
, &path
);
1037 rs
->sr_err
= apply_modify_to_entry(entry
, modlst
, op
, rs
);
1038 if(rs
->sr_err
== LDAP_SUCCESS
) {
1040 spew_res
= spew_entry(entry
, &path
, 1, &save_errno
);
1041 if(spew_res
== -1) {
1042 Debug( LDAP_DEBUG_ANY
,
1043 "%s ldif_back_modify: could not output entry \"%s\": %s\n",
1044 op
->o_log_prefix
, entry
->e_name
.bv_val
, STRERROR( save_errno
) );
1045 rs
->sr_err
= LDAP_UNWILLING_TO_PERFORM
;
1049 entry_free( entry
);
1050 SLAP_FREE( path
.bv_val
);
1054 ldap_pvt_thread_rdwr_wunlock(&li
->li_rdwr
);
1055 send_ldap_result(op
, rs
);
1056 slap_graduate_commit_csn( op
);
1060 static int ldif_back_delete(Operation
*op
, SlapReply
*rs
) {
1061 struct ldif_info
*li
= (struct ldif_info
*) op
->o_bd
->be_private
;
1065 if ( BER_BVISEMPTY( &op
->o_csn
)) {
1067 char csnbuf
[LDAP_LUTIL_CSNSTR_BUFSIZE
];
1069 csn
.bv_val
= csnbuf
;
1070 csn
.bv_len
= sizeof( csnbuf
);
1071 slap_get_csn( op
, &csn
, 1 );
1074 ldap_pvt_thread_rdwr_wlock(&li
->li_rdwr
);
1076 dn2path( op
->o_bd
, &op
->o_req_ndn
, &path
);
1077 path
.bv_val
[path
.bv_len
- STRLENOF(LDIF
)] = '\0';
1078 res
= rmdir(path
.bv_val
);
1079 path
.bv_val
[path
.bv_len
- STRLENOF(LDIF
)] = LDIF_FILETYPE_SEP
;
1080 rs
->sr_err
= LDAP_SUCCESS
;
1084 rs
->sr_err
= LDAP_NOT_ALLOWED_ON_NONLEAF
;
1088 /* is leaf, go on */
1093 rs
->sr_err
= LDAP_UNWILLING_TO_PERFORM
;
1099 res
= unlink(path
.bv_val
);
1103 rs
->sr_err
= LDAP_NO_SUCH_OBJECT
;
1107 rs
->sr_err
= LDAP_UNWILLING_TO_PERFORM
;
1113 SLAP_FREE(path
.bv_val
);
1114 ldap_pvt_thread_rdwr_wunlock(&li
->li_rdwr
);
1115 send_ldap_result(op
, rs
);
1116 slap_graduate_commit_csn( op
);
1125 struct berval
*oldpath
)
1129 struct berval newpath
;
1131 dn2path( op
->o_bd
, &entry
->e_nname
, &newpath
);
1133 if((entry
== NULL
|| oldpath
->bv_val
== NULL
) || newpath
.bv_val
== NULL
) {
1134 /* some object doesn't exist */
1135 res
= LDAP_NO_SUCH_OBJECT
;
1137 else { /* do the modrdn */
1138 exists_res
= open(newpath
.bv_val
, O_RDONLY
);
1139 if(exists_res
== -1 && errno
== ENOENT
) {
1140 ldap_pvt_thread_mutex_lock( &entry2str_mutex
);
1141 res
= spew_entry(entry
, &newpath
, 0, NULL
);
1143 /* if this fails we should log something bad */
1144 res
= unlink( oldpath
->bv_val
);
1145 oldpath
->bv_val
[oldpath
->bv_len
- STRLENOF(".ldif")] = '\0';
1146 newpath
.bv_val
[newpath
.bv_len
- STRLENOF(".ldif")] = '\0';
1147 res
= rename( oldpath
->bv_val
, newpath
.bv_val
);
1152 res
= LDAP_NO_SUCH_OBJECT
;
1154 res
= LDAP_UNWILLING_TO_PERFORM
;
1155 unlink(newpath
.bv_val
); /* in case file was created */
1157 ldap_pvt_thread_mutex_unlock( &entry2str_mutex
);
1159 else if(exists_res
) {
1160 int close_res
= close(exists_res
);
1161 res
= LDAP_ALREADY_EXISTS
;
1162 if(close_res
== -1) {
1163 /* log heinous error */
1167 res
= LDAP_UNWILLING_TO_PERFORM
;
1171 if(newpath
.bv_val
!= NULL
)
1172 SLAP_FREE(newpath
.bv_val
);
1177 ldif_back_modrdn(Operation
*op
, SlapReply
*rs
)
1179 struct ldif_info
*li
= (struct ldif_info
*) op
->o_bd
->be_private
;
1180 struct berval new_dn
= BER_BVNULL
, new_ndn
= BER_BVNULL
;
1181 struct berval p_dn
, old_path
;
1185 slap_mods_opattrs( op
, &op
->orr_modlist
, 1 );
1187 ldap_pvt_thread_rdwr_wlock( &li
->li_rdwr
);
1189 rc
= get_entry( op
, &entry
, &old_path
);
1190 if ( rc
== LDAP_SUCCESS
) {
1191 /* build new dn, and new ndn for the entry */
1192 if ( op
->oq_modrdn
.rs_newSup
!= NULL
) {
1193 struct berval op_dn
= op
->o_req_dn
,
1194 op_ndn
= op
->o_req_ndn
;
1198 p_dn
= *op
->oq_modrdn
.rs_newSup
;
1199 op
->o_req_dn
= *op
->oq_modrdn
.rs_newSup
;
1200 op
->o_req_ndn
= *op
->oq_modrdn
.rs_nnewSup
;
1201 rc
= get_entry( op
, &np
, NULL
);
1202 op
->o_req_dn
= op_dn
;
1203 op
->o_req_ndn
= op_ndn
;
1204 if ( rc
!= LDAP_SUCCESS
) {
1205 goto no_such_object
;
1209 dnParent( &entry
->e_name
, &p_dn
);
1211 build_new_dn( &new_dn
, &p_dn
, &op
->oq_modrdn
.rs_newrdn
, NULL
);
1212 dnNormalize( 0, NULL
, NULL
, &new_dn
, &new_ndn
, NULL
);
1213 ber_memfree_x( entry
->e_name
.bv_val
, NULL
);
1214 ber_memfree_x( entry
->e_nname
.bv_val
, NULL
);
1215 entry
->e_name
= new_dn
;
1216 entry
->e_nname
= new_ndn
;
1218 /* perform the modifications */
1219 rc
= apply_modify_to_entry( entry
, op
->orr_modlist
, op
, rs
);
1220 if ( rc
== LDAP_SUCCESS
)
1221 rc
= ldif_move_entry( op
, entry
, &old_path
);
1224 entry_free( entry
);
1225 SLAP_FREE( old_path
.bv_val
);
1229 ldap_pvt_thread_rdwr_wunlock( &li
->li_rdwr
);
1231 send_ldap_result( op
, rs
);
1232 slap_graduate_commit_csn( op
);
1237 /* Return LDAP_SUCCESS IFF we retrieve the specified entry. */
1239 ldif_back_entry_get(
1243 AttributeDescription
*at
,
1247 struct ldif_info
*li
= (struct ldif_info
*) op
->o_bd
->be_private
;
1248 struct berval op_dn
= op
->o_req_dn
, op_ndn
= op
->o_req_ndn
;
1251 assert( ndn
!= NULL
);
1252 assert( !BER_BVISNULL( ndn
) );
1254 ldap_pvt_thread_rdwr_rlock( &li
->li_rdwr
);
1255 op
->o_req_dn
= *ndn
;
1256 op
->o_req_ndn
= *ndn
;
1257 rc
= get_entry( op
, e
, NULL
);
1258 op
->o_req_dn
= op_dn
;
1259 op
->o_req_ndn
= op_ndn
;
1260 ldap_pvt_thread_rdwr_runlock( &li
->li_rdwr
);
1262 if ( rc
== LDAP_SUCCESS
&& oc
&& !is_entry_objectclass_or_sub( *e
, oc
) ) {
1263 rc
= LDAP_NO_SUCH_ATTRIBUTE
;
1274 static int ldif_tool_entry_open(BackendDB
*be
, int mode
) {
1275 struct ldif_info
*li
= (struct ldif_info
*) be
->be_private
;
1276 li
->li_tool_current
= 0;
1280 static int ldif_tool_entry_close(BackendDB
* be
) {
1281 struct ldif_info
*li
= (struct ldif_info
*) be
->be_private
;
1283 SLAP_FREE(li
->li_tool_cookie
.entries
);
1287 static ID
ldif_tool_entry_next(BackendDB
*be
)
1289 struct ldif_info
*li
= (struct ldif_info
*) be
->be_private
;
1290 if(li
->li_tool_current
>= li
->li_tool_cookie
.eind
)
1293 return ++li
->li_tool_current
;
1297 ldif_tool_entry_first(BackendDB
*be
)
1299 struct ldif_info
*li
= (struct ldif_info
*) be
->be_private
;
1301 if(li
->li_tool_cookie
.entries
== NULL
) {
1305 op
.o_req_dn
= *be
->be_suffix
;
1306 op
.o_req_ndn
= *be
->be_nsuffix
;
1307 op
.ors_scope
= LDAP_SCOPE_SUBTREE
;
1308 li
->li_tool_cookie
.op
= &op
;
1309 (void)enum_tree( &li
->li_tool_cookie
);
1310 li
->li_tool_cookie
.op
= NULL
;
1312 return ldif_tool_entry_next( be
);
1315 static Entry
* ldif_tool_entry_get(BackendDB
* be
, ID id
) {
1316 struct ldif_info
*li
= (struct ldif_info
*) be
->be_private
;
1319 if(id
> li
->li_tool_cookie
.eind
|| id
< 1)
1322 e
= li
->li_tool_cookie
.entries
[id
- 1];
1323 li
->li_tool_cookie
.entries
[id
- 1] = NULL
;
1328 static ID
ldif_tool_entry_put(BackendDB
* be
, Entry
* e
, struct berval
*text
) {
1329 struct berval leaf_path
= BER_BVNULL
;
1332 int res
= LDAP_SUCCESS
;
1334 dn2path( be
, &e
->e_nname
, &leaf_path
);
1336 if(leaf_path
.bv_val
!= NULL
) {
1337 struct berval base
= BER_BVNULL
;
1338 /* build path to container, and path to ldif of container */
1339 get_parent_path(&leaf_path
, &base
);
1341 statres
= stat(base
.bv_val
, &stats
); /* check if container exists */
1342 if(statres
== -1 && errno
== ENOENT
) { /* container missing */
1343 base
.bv_val
[base
.bv_len
] = LDIF_FILETYPE_SEP
;
1344 statres
= stat(base
.bv_val
, &stats
); /* check for leaf node */
1345 base
.bv_val
[base
.bv_len
] = '\0';
1346 if(statres
== -1 && errno
== ENOENT
) {
1347 res
= LDAP_NO_SUCH_OBJECT
; /* parent doesn't exist */
1349 else if(statres
!= -1) { /* create parent */
1350 int mkdirres
= mkdir(base
.bv_val
, 0750);
1351 if(mkdirres
== -1) {
1352 res
= LDAP_UNWILLING_TO_PERFORM
;
1356 res
= LDAP_UNWILLING_TO_PERFORM
;
1357 }/* container was possibly created, move on to add the entry */
1358 if(res
== LDAP_SUCCESS
) {
1359 statres
= stat(leaf_path
.bv_val
, &stats
);
1360 if(statres
== -1 && errno
== ENOENT
) {
1361 res
= spew_entry(e
, &leaf_path
, 0, NULL
);
1363 else /* it already exists */
1364 res
= LDAP_ALREADY_EXISTS
;
1366 SLAP_FREE(base
.bv_val
);
1367 SLAP_FREE(leaf_path
.bv_val
);
1370 if(res
== LDAP_SUCCESS
) {
1381 ldif_back_db_init( BackendDB
*be
, ConfigReply
*cr
)
1383 struct ldif_info
*li
;
1385 li
= ch_calloc( 1, sizeof(struct ldif_info
) );
1386 be
->be_private
= li
;
1387 be
->be_cf_ocs
= ldifocs
;
1388 ldap_pvt_thread_rdwr_init(&li
->li_rdwr
);
1389 SLAP_DBFLAGS( be
) |= SLAP_DBFLAG_ONE_SUFFIX
;
1394 ldif_back_db_destroy( Backend
*be
, ConfigReply
*cr
)
1396 struct ldif_info
*li
= be
->be_private
;
1398 ch_free(li
->li_base_path
.bv_val
);
1399 ldap_pvt_thread_rdwr_destroy(&li
->li_rdwr
);
1400 free( be
->be_private
);
1405 ldif_back_db_open( Backend
*be
, ConfigReply
*cr
)
1407 struct ldif_info
*li
= (struct ldif_info
*) be
->be_private
;
1408 if( BER_BVISEMPTY(&li
->li_base_path
)) {/* missing base path */
1409 Debug( LDAP_DEBUG_ANY
, "missing base path for back-ldif\n", 0, 0, 0);
1416 ldif_back_initialize(
1420 static char *controls
[] = {
1421 LDAP_CONTROL_MANAGEDSAIT
,
1427 SLAP_BFLAG_INCREMENT
|
1428 SLAP_BFLAG_REFERRALS
;
1430 bi
->bi_controls
= controls
;
1437 bi
->bi_db_init
= ldif_back_db_init
;
1438 bi
->bi_db_config
= config_generic_wrapper
;
1439 bi
->bi_db_open
= ldif_back_db_open
;
1440 bi
->bi_db_close
= 0;
1441 bi
->bi_db_destroy
= ldif_back_db_destroy
;
1443 bi
->bi_op_bind
= ldif_back_bind
;
1444 bi
->bi_op_unbind
= 0;
1445 bi
->bi_op_search
= ldif_back_search
;
1446 bi
->bi_op_compare
= 0;
1447 bi
->bi_op_modify
= ldif_back_modify
;
1448 bi
->bi_op_modrdn
= ldif_back_modrdn
;
1449 bi
->bi_op_add
= ldif_back_add
;
1450 bi
->bi_op_delete
= ldif_back_delete
;
1451 bi
->bi_op_abandon
= 0;
1453 bi
->bi_extended
= 0;
1455 bi
->bi_chk_referrals
= ldif_back_referrals
;
1457 bi
->bi_connection_init
= 0;
1458 bi
->bi_connection_destroy
= 0;
1460 bi
->bi_entry_get_rw
= ldif_back_entry_get
;
1462 #if 0 /* NOTE: uncomment to completely disable access control */
1463 bi
->bi_access_allowed
= slap_access_always_allowed
;
1466 bi
->bi_tool_entry_open
= ldif_tool_entry_open
;
1467 bi
->bi_tool_entry_close
= ldif_tool_entry_close
;
1468 bi
->bi_tool_entry_first
= ldif_tool_entry_first
;
1469 bi
->bi_tool_entry_next
= ldif_tool_entry_next
;
1470 bi
->bi_tool_entry_get
= ldif_tool_entry_get
;
1471 bi
->bi_tool_entry_put
= ldif_tool_entry_put
;
1472 bi
->bi_tool_entry_reindex
= 0;
1473 bi
->bi_tool_sync
= 0;
1475 bi
->bi_tool_dn2id_get
= 0;
1476 bi
->bi_tool_entry_modify
= 0;
1478 bi
->bi_cf_ocs
= ldifocs
;
1480 rc
= config_register_schema( ldifcfg
, ldifocs
);
1481 if ( rc
) return rc
;