Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
O
OpenLDAP
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
David Barchiesi
OpenLDAP
Commits
ab1a0237
Commit
ab1a0237
authored
16 years ago
by
Quanah Gibson-Mount
Browse files
Options
Downloads
Patches
Plain Diff
ITS#5408,ITS#5319,ITS#5329
parent
210b7225
No related branches found
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
servers/slapd/back-ldif/ldif.c
+971
-721
971 additions, 721 deletions
servers/slapd/back-ldif/ldif.c
with
971 additions
and
721 deletions
servers/slapd/back-ldif/ldif.c
+
971
−
721
View file @
ab1a0237
...
...
@@ -31,24 +31,37 @@
#include
"lutil.h"
#include
"config.h"
typedef
struct
enumCookie
{
Operation
*
op
;
SlapReply
*
rs
;
Entry
**
entries
;
ID
elen
;
ID
eind
;
}
enumCookie
;
struct
ldif_tool
{
Entry
**
entries
;
/* collected by bi_tool_entry_first() */
ID
elen
;
/* length of entries[] array */
ID
ecount
;
/* number of
entries
*/
ID
ecurrent
;
/* bi_tool_entry_next() position */
# define ENTRY_BUFF_INCREMENT 500
/* initial entries[] length */
};
/* Per-database data */
struct
ldif_info
{
struct
berval
li_base_path
;
enumCookie
li_tool_cookie
;
ID
li_tool_current
;
ldap_pvt_thread_rdwr_t
li_rdwr
;
struct
berval
li_base_path
;
/* database directory */
struct
ldif_tool
li_tool
;
/* for slap tools */
/*
* Read-only LDAP requests readlock li_rdwr for filesystem input.
* Update requests first lock li_modop_mutex for filesystem I/O,
* and then writelock li_rdwr as well for filesystem output.
* This allows update requests to do callbacks that acquire
* read locks, e.g. access controls that inspect entries.
* (An alternative would be recursive read/write locks.)
*/
ldap_pvt_thread_mutex_t
li_modop_mutex
;
/* serialize update requests */
ldap_pvt_thread_rdwr_t
li_rdwr
;
/* no other I/O when writing */
};
#ifdef _WIN32
#define mkdir(a,b) mkdir(a)
#define move_file(from, to) (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING))
#else
#define move_file(from, to) rename(from, to)
#endif
#define move_dir(from, to) rename(from, to)
#define LDIF ".ldif"
...
...
@@ -58,11 +71,10 @@ struct ldif_info {
* Unsafe/translated characters in the filesystem.
*
* LDIF_UNSAFE_CHAR(c) returns true if the character c is not to be used
* in relative filenames, except it should accept '\\'
even if unsafe and
*
need not reject '{' and '}'
. The value should be a constant expression.
* in relative filenames, except it should accept '\\'
, '{' and '}' even
*
if unsafe
. The value should be a constant expression.
*
* If '\\' is unsafe, #define LDIF_ESCAPE_CHAR as a safe character.
*
* If '{' and '}' are unsafe, #define IX_FSL/IX_FSR as safe characters.
* (Not digits, '-' or '+'. IX_FSL == IX_FSR is allowed.)
*
...
...
@@ -87,7 +99,7 @@ struct ldif_info {
#else
/* _WIN32 */
/* Windows version - Microsoft's list of unsafe characters, except '\\' */
#define LDIF_ESCAPE_CHAR '^'
#define LDIF_ESCAPE_CHAR '^'
/* Not '\\' (unsafe on Windows) */
#define LDIF_UNSAFE_CHAR(c) \
((c) == '/' || (c) == ':' || \
(c) == '<' || (c) == '>' || (c) == '"' || \
...
...
@@ -132,8 +144,19 @@ struct ldif_info {
(!(LDIF_UNSAFE_CHAR(x) || (x) == '\\' || (x) == IX_DNL || (x) == IX_DNR) \
&& (c) == (x))
/* Collect other "safe char" tests here, until someone needs a fix. */
enum
{
eq_unsafe
=
LDIF_UNSAFE_CHAR
(
'='
),
safe_filenames
=
STRLENOF
(
""
LDAP_DIRSEP
""
)
==
1
&&
!
(
LDIF_UNSAFE_CHAR
(
'-'
)
||
/* for "{-1}frontend" in bconfig.c */
LDIF_UNSAFE_CHAR
(
LDIF_ESCAPE_CHAR
)
||
LDIF_UNSAFE_CHAR
(
IX_FSL
)
||
LDIF_UNSAFE_CHAR
(
IX_FSR
))
};
/* Sanity check: Try to force a compilation error if !safe_filenames */
typedef
struct
{
int
assert_safe_filenames
:
safe_filenames
?
2
:
-
2
;
}
assert_safe_filenames
[
safe_filenames
?
2
:
-
2
];
#define ENTRY_BUFF_INCREMENT 500
static
ConfigTable
ldifcfg
[]
=
{
{
"directory"
,
"dir"
,
2
,
2
,
0
,
ARG_BERVAL
|
ARG_OFFSET
,
...
...
@@ -156,6 +179,10 @@ static ConfigOCs ldifocs[] = {
};
/*
* Handle file/directory names.
*/
/* Set *res = LDIF filename path for the normalized DN */
static
void
dn2path
(
BackendDB
*
be
,
struct
berval
*
dn
,
struct
berval
*
res
)
...
...
@@ -215,48 +242,157 @@ dn2path( BackendDB *be, struct berval *dn, struct berval *res )
assert
(
res
->
bv_len
<=
len
);
}
static
char
*
slurp_file
(
int
fd
)
{
int
read_chars_total
=
0
;
int
read_chars
=
0
;
int
entry_size
;
char
*
entry
;
char
*
entry_pos
;
/*
* *dest = dupbv(<dir + LDAP_DIRSEP>), plus room for <more>-sized filename.
* Return pointer past the dirname.
*/
static
char
*
fullpath_alloc
(
struct
berval
*
dest
,
const
struct
berval
*
dir
,
ber_len_t
more
)
{
char
*
s
=
SLAP_MALLOC
(
dir
->
bv_len
+
more
+
2
);
dest
->
bv_val
=
s
;
if
(
s
==
NULL
)
{
dest
->
bv_len
=
0
;
Debug
(
LDAP_DEBUG_ANY
,
"back-ldif: out of memory
\n
"
,
0
,
0
,
0
);
}
else
{
s
=
lutil_strcopy
(
dest
->
bv_val
,
dir
->
bv_val
);
*
s
++
=
LDAP_DIRSEP
[
0
];
*
s
=
'\0'
;
dest
->
bv_len
=
s
-
dest
->
bv_val
;
}
return
s
;
}
/*
* Append filename to fullpath_alloc() dirname or replace previous filename.
* dir_end = fullpath_alloc() return value.
*/
#define FILL_PATH(fpath, dir_end, filename) \
((fpath)->bv_len = lutil_strcopy(dir_end, filename) - (fpath)->bv_val)
/* .ldif entry filename length <-> subtree dirname length. */
#define ldif2dir_len(bv) ((bv).bv_len -= STRLENOF(LDIF))
#define dir2ldif_len(bv) ((bv).bv_len += STRLENOF(LDIF))
/* .ldif entry filename <-> subtree dirname, both with dirname length. */
#define ldif2dir_name(bv) ((bv).bv_val[(bv).bv_len] = '\0')
#define dir2ldif_name(bv) ((bv).bv_val[(bv).bv_len] = LDIF_FILETYPE_SEP)
/* Get the parent directory path, plus the LDIF suffix overwritten by a \0. */
static
int
get_parent_path
(
struct
berval
*
dnpath
,
struct
berval
*
res
)
{
ber_len_t
i
=
dnpath
->
bv_len
;
while
(
i
>
0
&&
dnpath
->
bv_val
[
--
i
]
!=
LDAP_DIRSEP
[
0
]
)
;
if
(
res
==
NULL
)
{
res
=
dnpath
;
}
else
{
res
->
bv_val
=
SLAP_MALLOC
(
i
+
1
+
STRLENOF
(
LDIF
)
);
if
(
res
->
bv_val
==
NULL
)
return
LDAP_OTHER
;
AC_MEMCPY
(
res
->
bv_val
,
dnpath
->
bv_val
,
i
);
}
res
->
bv_len
=
i
;
strcpy
(
res
->
bv_val
+
i
,
LDIF
);
res
->
bv_val
[
i
]
=
'\0'
;
return
LDAP_SUCCESS
;
}
/* Make temporary filename pattern for mkstemp() based on dnpath. */
static
char
*
ldif_tempname
(
const
struct
berval
*
dnpath
)
{
static
const
char
suffix
[]
=
".XXXXXX"
;
ber_len_t
len
=
dnpath
->
bv_len
-
STRLENOF
(
LDIF
);
char
*
name
=
SLAP_MALLOC
(
len
+
sizeof
(
suffix
)
);
if
(
name
!=
NULL
)
{
AC_MEMCPY
(
name
,
dnpath
->
bv_val
,
len
);
strcpy
(
name
+
len
,
suffix
);
}
return
name
;
}
/*
* Read a file, or stat() it if datap == NULL. Allocate and fill *datap.
* Return LDAP_SUCCESS, LDAP_NO_SUCH_OBJECT (no such file), or another error.
*/
static
int
ldif_read_file
(
const
char
*
path
,
char
**
datap
)
{
int
rc
,
fd
,
len
;
int
res
=
-
1
;
/* 0:success, <0:error, >0:file too big/growing. */
struct
stat
st
;
char
*
data
=
NULL
,
*
ptr
;
fstat
(
fd
,
&
st
);
entry_size
=
st
.
st_size
;
entry
=
ch_malloc
(
entry_size
+
1
);
entry_pos
=
entry
;
while
(
1
)
{
read_chars
=
read
(
fd
,
(
void
*
)
entry_pos
,
entry_size
-
read_chars_total
);
if
(
read_chars
==
-
1
)
{
SLAP_FREE
(
entry
);
return
NULL
;
}
if
(
read_chars
==
0
)
{
entry
[
read_chars_total
]
=
'\0'
;
break
;
if
(
datap
==
NULL
)
{
res
=
stat
(
path
,
&
st
);
goto
done
;
}
fd
=
open
(
path
,
O_RDONLY
);
if
(
fd
>=
0
)
{
if
(
fstat
(
fd
,
&
st
)
==
0
)
{
if
(
st
.
st_size
>
INT_MAX
-
2
)
{
res
=
1
;
}
else
{
len
=
st
.
st_size
+
1
;
/* +1 detects file size > st.st_size */
*
datap
=
data
=
ptr
=
SLAP_MALLOC
(
len
+
1
);
if
(
ptr
!=
NULL
)
{
while
(
len
&&
(
res
=
read
(
fd
,
ptr
,
len
))
)
{
if
(
res
>
0
)
{
len
-=
res
;
ptr
+=
res
;
}
else
if
(
errno
!=
EINTR
)
{
break
;
}
}
*
ptr
=
'\0'
;
}
}
}
else
{
read_chars_total
+=
read_chars
;
entry_pos
+=
read_chars
;
if
(
close
(
fd
)
<
0
)
res
=
-
1
;
}
done:
if
(
res
==
0
)
{
Debug
(
LDAP_DEBUG_TRACE
,
"ldif_read_file: %s:
\"
%s
\"\n
"
,
datap
?
"read entry file"
:
"entry file exists"
,
path
,
0
);
rc
=
LDAP_SUCCESS
;
}
else
{
if
(
res
<
0
&&
errno
==
ENOENT
)
{
Debug
(
LDAP_DEBUG_TRACE
,
"ldif_read_file: "
"no entry file
\"
%s
\"\n
"
,
path
,
0
,
0
);
rc
=
LDAP_NO_SUCH_OBJECT
;
}
else
{
const
char
*
msg
=
res
<
0
?
STRERROR
(
errno
)
:
"bad stat() size"
;
Debug
(
LDAP_DEBUG_ANY
,
"ldif_read_file: %s for
\"
%s
\"\n
"
,
msg
,
path
,
0
);
rc
=
LDAP_OTHER
;
}
if
(
data
!=
NULL
)
SLAP_FREE
(
data
);
}
return
entry
;
return
rc
;
}
/*
* return nonnegative for success or -1 for error
* do not return numbers less than -1
*/
static
int
spew_file
(
int
fd
,
char
*
spew
,
int
len
)
{
static
int
spew_file
(
int
fd
,
const
char
*
spew
,
int
len
,
int
*
save_errno
)
{
int
writeres
=
0
;
while
(
len
>
0
)
{
writeres
=
write
(
fd
,
spew
,
len
);
if
(
writeres
==
-
1
)
{
return
-
1
;
*
save_errno
=
errno
;
if
(
*
save_errno
!=
EINTR
)
break
;
}
else
{
spew
+=
writeres
;
...
...
@@ -266,412 +402,603 @@ static int spew_file(int fd, char * spew, int len) {
return
writeres
;
}
/* Write an entry LDIF file. Create parentdir first if non-NULL. */
static
int
spew_entry
(
Entry
*
e
,
struct
berval
*
path
,
int
dolock
,
int
*
save_errnop
)
ldif_write_entry
(
Operation
*
op
,
Entry
*
e
,
const
struct
berval
*
path
,
const
char
*
parentdir
,
const
char
**
text
)
{
int
rs
,
save_errno
=
0
;
int
openres
;
int
res
,
spew_res
;
int
entry_length
;
char
*
entry_as_string
;
char
*
tmpfname
=
NULL
;
tmpfname
=
ch_malloc
(
path
->
bv_len
+
STRLENOF
(
"XXXXXX"
)
+
1
);
AC_MEMCPY
(
tmpfname
,
path
->
bv_val
,
path
->
bv_len
);
AC_MEMCPY
(
&
tmpfname
[
path
->
bv_len
],
"XXXXXX"
,
STRLENOF
(
"XXXXXX"
)
+
1
);
openres
=
mkstemp
(
tmpfname
);
if
(
openres
==
-
1
)
{
int
rc
=
LDAP_OTHER
,
res
,
save_errno
=
0
;
int
fd
,
entry_length
;
char
*
entry_as_string
,
*
tmpfname
;
if
(
op
->
o_abandon
)
return
SLAPD_ABANDON
;
if
(
parentdir
!=
NULL
&&
mkdir
(
parentdir
,
0750
)
<
0
)
{
save_errno
=
errno
;
rs
=
LDAP_UNWILLING_TO_PERFORM
;
Debug
(
LDAP_DEBUG_ANY
,
"could not create tmpfile
\"
%s
\"
: %s
\n
"
,
tmpfname
,
STRERROR
(
save_errno
),
0
);
Debug
(
LDAP_DEBUG_ANY
,
"ldif_write_entry: %s
\"
%s
\"
: %s
\n
"
,
"cannot create parent directory"
,
parentdir
,
STRERROR
(
save_errno
)
);
*
text
=
"internal error (cannot create parent directory)"
;
return
rc
;
}
tmpfname
=
ldif_tempname
(
path
);
fd
=
tmpfname
==
NULL
?
-
1
:
mkstemp
(
tmpfname
);
if
(
fd
<
0
)
{
save_errno
=
errno
;
Debug
(
LDAP_DEBUG_ANY
,
"ldif_write_entry: %s for
\"
%s
\"
: %s
\n
"
,
"cannot create file"
,
e
->
e_dn
,
STRERROR
(
save_errno
)
);
*
text
=
"internal error (cannot create file)"
;
}
else
{
ber_len_t
dn_len
=
e
->
e_name
.
bv_len
;
struct
berval
rdn
;
int
tmp
;
/* Only save the RDN onto disk */
dnRdn
(
&
e
->
e_name
,
&
rdn
);
if
(
rdn
.
bv_len
!=
e
->
e_name
.
bv
_len
)
{
if
(
rdn
.
bv_len
!=
dn
_len
)
{
e
->
e_name
.
bv_val
[
rdn
.
bv_len
]
=
'\0'
;
tmp
=
e
->
e_name
.
bv_len
;
e
->
e_name
.
bv_len
=
rdn
.
bv_len
;
rdn
.
bv_len
=
tmp
;
}
spew_res
=
-
2
;
if
(
dolock
)
{
ldap_pvt_thread_mutex_lock
(
&
entry2str_mutex
);
}
entry_as_string
=
entry2str
(
e
,
&
entry_length
);
if
(
entry_as_string
!=
NULL
)
{
spew_res
=
spew_file
(
openres
,
entry_as_string
,
entry_length
);
if
(
spew_res
==
-
1
)
{
save_errno
=
errno
;
}
}
if
(
dolock
)
{
ldap_pvt_thread_mutex_unlock
(
&
entry2str_mutex
);
}
res
=
-
2
;
ldap_pvt_thread_mutex_lock
(
&
entry2str_mutex
);
entry_as_string
=
entry2str
(
e
,
&
entry_length
);
if
(
entry_as_string
!=
NULL
)
res
=
spew_file
(
fd
,
entry_as_string
,
entry_length
,
&
save_errno
);
ldap_pvt_thread_mutex_unlock
(
&
entry2str_mutex
);
/* Restore full DN */
if
(
rdn
.
bv_len
!=
e
->
e_name
.
bv
_len
)
{
e
->
e_name
.
bv_val
[
e
->
e_name
.
bv_len
]
=
','
;
e
->
e_name
.
bv_len
=
r
dn
.
bv
_len
;
if
(
rdn
.
bv_len
!=
dn
_len
)
{
e
->
e_name
.
bv_val
[
rdn
.
bv_len
]
=
','
;
e
->
e_name
.
bv_len
=
dn_len
;
}
res
=
close
(
openres
);
rs
=
LDAP_UNWILLING_TO_PERFORM
;
if
(
spew_res
>
-
2
)
{
if
(
res
==
-
1
||
spew_res
==
-
1
)
{
if
(
save_errno
==
0
)
{
save_errno
=
errno
;
}
Debug
(
LDAP_DEBUG_ANY
,
"write error to tmpfile
\"
%s
\"
: %s
\n
"
,
tmpfname
,
STRERROR
(
save_errno
),
0
);
if
(
close
(
fd
)
<
0
&&
res
>=
0
)
{
res
=
-
1
;
save_errno
=
errno
;
}
if
(
res
>=
0
)
{
if
(
move_file
(
tmpfname
,
path
->
bv_val
)
==
0
)
{
Debug
(
LDAP_DEBUG_TRACE
,
"ldif_write_entry: "
"wrote entry
\"
%s
\"\n
"
,
e
->
e_name
.
bv_val
,
0
,
0
);
rc
=
LDAP_SUCCESS
;
}
else
{
#ifdef _WIN32
/* returns 0 on failure, nonzero on success */
res
=
MoveFileEx
(
tmpfname
,
path
->
bv_val
,
MOVEFILE_REPLACE_EXISTING
)
==
0
;
#else
res
=
rename
(
tmpfname
,
path
->
bv_val
);
#endif
if
(
res
==
0
)
{
rs
=
LDAP_SUCCESS
;
}
else
{
save_errno
=
errno
;
switch
(
save_errno
)
{
case
ENOENT
:
rs
=
LDAP_NO_SUCH_OBJECT
;
break
;
default:
break
;
}
}
save_errno
=
errno
;
Debug
(
LDAP_DEBUG_ANY
,
"ldif_write_entry: "
"could not put entry file for
\"
%s
\"
in place: %s
\n
"
,
e
->
e_name
.
bv_val
,
STRERROR
(
save_errno
),
0
);
*
text
=
"internal error (could not put entry file in place)"
;
}
}
else
if
(
res
==
-
1
)
{
Debug
(
LDAP_DEBUG_ANY
,
"ldif_write_entry: %s
\"
%s
\"
: %s
\n
"
,
"write error to"
,
tmpfname
,
STRERROR
(
save_errno
)
);
*
text
=
"internal error (write error to entry file)"
;
}
if
(
r
s
!=
LDAP_SUCCESS
)
{
if
(
r
c
!=
LDAP_SUCCESS
)
{
unlink
(
tmpfname
);
}
}
ch_free
(
tmpfname
);
if
(
rs
!=
LDAP_SUCCESS
&&
save_errnop
!=
NULL
)
{
*
save_errnop
=
save_errno
;
}
return
rs
;
if
(
tmpfname
)
SLAP_FREE
(
tmpfname
);
return
rc
;
}
static
Entry
*
get_entry_for_fd
(
int
fd
,
/*
* Read the entry at path, or if entryp==NULL just see if it exists.
* pdn and pndn are the parent's DN and normalized DN, or both NULL.
* Return an LDAP result code.
*/
static
int
ldif_read_entry
(
Operation
*
op
,
const
char
*
path
,
struct
berval
*
pdn
,
struct
berval
*
pndn
)
struct
berval
*
pndn
,
Entry
**
entryp
,
const
char
**
text
)
{
char
*
entry
=
(
char
*
)
slurp_file
(
fd
);
Entry
*
ldentry
=
NULL
;
/* error reading file */
if
(
entry
==
NULL
)
{
goto
return_value
;
}
int
rc
;
Entry
*
entry
;
char
*
entry_as_string
;
struct
berval
rdn
;
ldentry
=
str2entry
(
entry
);
if
(
ldentry
)
{
struct
berval
rdn
;
rdn
=
ldentry
->
e_name
;
build_new_dn
(
&
ldentry
->
e_name
,
pdn
,
&
rdn
,
NULL
);
ch_free
(
rdn
.
bv_val
);
rdn
=
ldentry
->
e_nname
;
build_new_dn
(
&
ldentry
->
e_nname
,
pndn
,
&
rdn
,
NULL
);
ch_free
(
rdn
.
bv_val
);
}
/* TODO: Does slapd prevent Abandon of Bind as per rfc4511?
* If so we need not check for LDAP_REQ_BIND here.
*/
if
(
op
->
o_abandon
&&
op
->
o_tag
!=
LDAP_REQ_BIND
)
return
SLAPD_ABANDON
;
return_value:
if
(
fd
!=
-
1
)
{
if
(
close
(
fd
)
!=
0
)
{
/* log error */
rc
=
ldif_read_file
(
path
,
entryp
?
&
entry_as_string
:
NULL
);
switch
(
rc
)
{
case
LDAP_SUCCESS
:
if
(
entryp
==
NULL
)
break
;
*
entryp
=
entry
=
str2entry
(
entry_as_string
);
SLAP_FREE
(
entry_as_string
);
if
(
entry
==
NULL
)
{
rc
=
LDAP_OTHER
;
if
(
text
!=
NULL
)
*
text
=
"internal error (cannot parse some entry file)"
;
break
;
}
if
(
pdn
==
NULL
||
BER_BVISEMPTY
(
pdn
)
)
break
;
/* Append parent DN to DN from LDIF file */
rdn
=
entry
->
e_name
;
build_new_dn
(
&
entry
->
e_name
,
pdn
,
&
rdn
,
NULL
);
SLAP_FREE
(
rdn
.
bv_val
);
rdn
=
entry
->
e_nname
;
build_new_dn
(
&
entry
->
e_nname
,
pndn
,
&
rdn
,
NULL
);
SLAP_FREE
(
rdn
.
bv_val
);
break
;
case
LDAP_OTHER
:
if
(
text
!=
NULL
)
*
text
=
entryp
?
"internal error (cannot read some entry file)"
:
"internal error (cannot stat some entry file)"
;
break
;
}
if
(
entry
!=
NULL
)
SLAP_FREE
(
entry
);
return
ldentry
;
return
rc
;
}
/*
* Read the operation's entry, or if entryp==NULL just see if it exists.
* Return an LDAP result code. May set *text to a message on failure.
* If pathp is non-NULL, set it to the entry filename on success.
*/
static
int
get_entry
(
Operation
*
op
,
Entry
**
entryp
,
struct
berval
*
pathp
)
struct
berval
*
pathp
,
const
char
**
text
)
{
int
rc
;
struct
berval
path
,
pdn
,
pndn
;
int
fd
;
dnParent
(
&
op
->
o_req_dn
,
&
pdn
);
dnParent
(
&
op
->
o_req_ndn
,
&
pndn
);
dnParent
(
&
op
->
o_req_dn
,
&
pdn
);
dnParent
(
&
op
->
o_req_ndn
,
&
pndn
);
dn2path
(
op
->
o_bd
,
&
op
->
o_req_ndn
,
&
path
);
fd
=
open
(
path
.
bv_val
,
O_RDONLY
);
/* error opening file (mebbe should log error) */
if
(
fd
==
-
1
&&
(
errno
!=
ENOENT
||
op
->
o_tag
!=
LDAP_REQ_ADD
)
)
{
Debug
(
LDAP_DEBUG_ANY
,
"failed to open file
\"
%s
\"
: %s
\n
"
,
path
.
bv_val
,
STRERROR
(
errno
),
0
);
}
*
entryp
=
fd
<
0
?
NULL
:
get_entry_for_fd
(
fd
,
&
pdn
,
&
pndn
);
rc
=
*
entryp
?
LDAP_SUCCESS
:
LDAP_NO_SUCH_OBJECT
;
rc
=
ldif_read_entry
(
op
,
path
.
bv_val
,
&
pdn
,
&
pndn
,
entryp
,
text
);
if
(
rc
==
LDAP_SUCCESS
&&
pathp
!=
NULL
)
{
*
pathp
=
path
;
}
else
{
SLAP_FREE
(
path
.
bv_val
);
SLAP_FREE
(
path
.
bv_val
);
}
return
rc
;
}
static
void
fullpath
(
struct
berval
*
base
,
struct
berval
*
name
,
struct
berval
*
res
)
{
char
*
ptr
;
res
->
bv_len
=
name
->
bv_len
+
base
->
bv_len
+
1
;
res
->
bv_val
=
ch_malloc
(
res
->
bv_len
+
1
);
strcpy
(
res
->
bv_val
,
base
->
bv_val
);
ptr
=
res
->
bv_val
+
base
->
bv_len
;
*
ptr
++
=
LDAP_DIRSEP
[
0
];
strcpy
(
ptr
,
name
->
bv_val
);
}
/*
* RDN-named directory entry, with special handling of "attr={num}val" RDNs.
* For sorting, filename "attr=val.ldif" is truncated to "attr="val\0ldif",
* and filename "attr={num}val.ldif" to "attr={\0um}val.ldif".
* Does not sort escaped chars correctly, would need to un-escape them.
*/
typedef
struct
bvlist
{
struct
bvlist
*
next
;
struct
berval
bv
;
struct
berval
num
;
int
inum
;
int
off
;
char
*
trunc
;
/* filename was truncated here */
int
inum
;
/* num from "attr={num}" in filename, or INT_MIN */
char
savech
;
/* original char at *trunc */
char
fname
;
/* variable length array BVL_NAME(bvl) = &fname */
# define BVL_NAME(bvl) ((char *) (bvl) + offsetof(bvlist, fname))
# define BVL_SIZE(namelen) (sizeof(bvlist) + (namelen))
}
bvlist
;
static
int
r_enum_tree
(
enumCookie
*
ck
,
struct
berval
*
path
,
int
base
,
struct
berval
*
pdn
,
struct
berval
*
pndn
)
static
int
ldif_send_entry
(
Operation
*
op
,
SlapReply
*
rs
,
Entry
*
e
,
int
scope
)
{
Entry
*
e
=
NULL
;
int
fd
=
0
,
rc
=
LDAP_SUCCESS
;
if
(
!
base
)
{
fd
=
open
(
path
->
bv_val
,
O_RDONLY
);
if
(
fd
<
0
)
{
Debug
(
LDAP_DEBUG_TRACE
,
"=> ldif_enum_tree: failed to open %s: %s
\n
"
,
path
->
bv_val
,
STRERROR
(
errno
),
0
);
return
LDAP_NO_SUCH_OBJECT
;
int
rc
=
LDAP_SUCCESS
;
if
(
scope
==
LDAP_SCOPE_BASE
||
scope
==
LDAP_SCOPE_SUBTREE
)
{
if
(
rs
==
NULL
)
{
/* Save the entry for tool mode */
struct
ldif_tool
*
tl
=
&
((
struct
ldif_info
*
)
op
->
o_bd
->
be_private
)
->
li_tool
;
if
(
tl
->
ecount
>=
tl
->
elen
)
{
/* Allocate/grow entries */
ID
elen
=
tl
->
elen
?
tl
->
elen
*
2
:
ENTRY_BUFF_INCREMENT
;
Entry
**
entries
=
(
Entry
**
)
SLAP_REALLOC
(
tl
->
entries
,
sizeof
(
Entry
*
)
*
elen
);
if
(
entries
==
NULL
)
{
Debug
(
LDAP_DEBUG_ANY
,
"ldif_send_entry: out of memory
\n
"
,
0
,
0
,
0
);
rc
=
LDAP_OTHER
;
goto
done
;
}
tl
->
elen
=
elen
;
tl
->
entries
=
entries
;
}
tl
->
entries
[
tl
->
ecount
++
]
=
e
;
return
rc
;
}
e
=
get_entry_for_fd
(
fd
,
pdn
,
pndn
);
if
(
!
e
)
{
Debug
(
LDAP_DEBUG_ANY
,
"=> ldif_enum_tree: failed to read entry for %s
\n
"
,
path
->
bv_val
,
0
,
0
);
return
LDAP_BUSY
;
else
if
(
!
get_manageDSAit
(
op
)
&&
is_entry_referral
(
e
)
)
{
/* Send a continuation reference.
* (ldif_back_referrals() handles baseobject referrals.)
* Don't check the filter since it's only a candidate.
*/
BerVarray
refs
=
get_entry_referrals
(
op
,
e
);
rs
->
sr_ref
=
referral_rewrite
(
refs
,
&
e
->
e_name
,
NULL
,
scope
);
rs
->
sr_entry
=
e
;
rc
=
send_search_reference
(
op
,
rs
);
ber_bvarray_free
(
rs
->
sr_ref
);
ber_bvarray_free
(
refs
);
rs
->
sr_ref
=
NULL
;
rs
->
sr_entry
=
NULL
;
}
if
(
ck
->
op
->
ors_scope
==
LDAP_SCOPE_BASE
||
ck
->
op
->
ors_scope
==
LDAP_SCOPE_SUBTREE
)
{
/* Send right away? */
if
(
ck
->
rs
)
{
/*
* if it's a referral, add it to the list of referrals. only do
* this for non-base searches, and don't check the filter
* explicitly here since it's only a candidate anyway.
*/
if
(
!
get_manageDSAit
(
ck
->
op
)
&&
ck
->
op
->
ors_scope
!=
LDAP_SCOPE_BASE
&&
is_entry_referral
(
e
)
)
{
BerVarray
erefs
=
get_entry_referrals
(
ck
->
op
,
e
);
ck
->
rs
->
sr_ref
=
referral_rewrite
(
erefs
,
&
e
->
e_name
,
NULL
,
ck
->
op
->
oq_search
.
rs_scope
==
LDAP_SCOPE_ONELEVEL
?
LDAP_SCOPE_BASE
:
LDAP_SCOPE_SUBTREE
);
ck
->
rs
->
sr_entry
=
e
;
rc
=
send_search_reference
(
ck
->
op
,
ck
->
rs
);
ber_bvarray_free
(
ck
->
rs
->
sr_ref
);
ber_bvarray_free
(
erefs
);
ck
->
rs
->
sr_ref
=
NULL
;
ck
->
rs
->
sr_entry
=
NULL
;
}
else
if
(
test_filter
(
ck
->
op
,
e
,
ck
->
op
->
ors_filter
)
==
LDAP_COMPARE_TRUE
)
{
ck
->
rs
->
sr_entry
=
e
;
ck
->
rs
->
sr_attrs
=
ck
->
op
->
ors_attrs
;
ck
->
rs
->
sr_flags
=
REP_ENTRY_MODIFIABLE
;
rc
=
send_search_entry
(
ck
->
op
,
ck
->
rs
);
ck
->
rs
->
sr_entry
=
NULL
;
}
fd
=
1
;
if
(
rc
)
goto
done
;
}
else
{
/* Queueing up for tool mode */
if
(
ck
->
entries
==
NULL
)
{
ck
->
entries
=
(
Entry
**
)
ch_malloc
(
sizeof
(
Entry
*
)
*
ENTRY_BUFF_INCREMENT
);
ck
->
elen
=
ENTRY_BUFF_INCREMENT
;
}
if
(
ck
->
eind
>=
ck
->
elen
)
{
/* grow entries if necessary */
ck
->
entries
=
(
Entry
**
)
ch_realloc
(
ck
->
entries
,
sizeof
(
Entry
*
)
*
(
ck
->
elen
)
*
2
);
ck
->
elen
*=
2
;
}
ck
->
entries
[
ck
->
eind
++
]
=
e
;
fd
=
0
;
}
}
else
{
fd
=
1
;
else
if
(
test_filter
(
op
,
e
,
op
->
ors_filter
)
==
LDAP_COMPARE_TRUE
)
{
rs
->
sr_entry
=
e
;
rs
->
sr_attrs
=
op
->
ors_attrs
;
rs
->
sr_flags
=
REP_ENTRY_MODIFIABLE
;
rc
=
send_search_entry
(
op
,
rs
);
rs
->
sr_entry
=
NULL
;
}
}
if
(
ck
->
op
->
ors_scope
!=
LDAP_SCOPE_BASE
)
{
DIR
*
dir_of_path
;
bvlist
*
list
=
NULL
,
*
ptr
;
done:
entry_free
(
e
);
return
rc
;
}
path
->
bv_len
-=
STRLENOF
(
LDIF
);
path
->
bv_val
[
path
->
bv_len
]
=
'\0'
;
/* Read LDIF directory <path> into <listp>. Set *fname_maxlenp. */
static
int
ldif_readdir
(
Operation
*
op
,
SlapReply
*
rs
,
const
struct
berval
*
path
,
bvlist
**
listp
,
ber_len_t
*
fname_maxlenp
)
{
int
rc
=
LDAP_SUCCESS
;
DIR
*
dir_of_path
;
dir_of_path
=
opendir
(
path
->
bv_val
);
if
(
dir_of_path
==
NULL
)
{
/* can't open directory */
if
(
errno
!=
ENOENT
)
{
/* it shouldn't be treated as an error
* only if the directory doesn't exist */
rc
=
LDAP_BUSY
;
Debug
(
LDAP_DEBUG_ANY
,
"=> ldif_enum_tree: failed to opendir %s (%d)
\n
"
,
path
->
bv_val
,
errno
,
0
);
}
goto
done
;
*
listp
=
NULL
;
*
fname_maxlenp
=
0
;
dir_of_path
=
opendir
(
path
->
bv_val
);
if
(
dir_of_path
==
NULL
)
{
int
save_errno
=
errno
;
struct
ldif_info
*
li
=
(
struct
ldif_info
*
)
op
->
o_bd
->
be_private
;
int
is_rootDSE
=
(
path
->
bv_len
==
li
->
li_base_path
.
bv_len
);
/* Absent directory is OK (leaf entry), except the database dir */
if
(
is_rootDSE
||
save_errno
!=
ENOENT
)
{
Debug
(
LDAP_DEBUG_ANY
,
"=> ldif_search_entry: failed to opendir
\"
%s
\"
: %s
\n
"
,
path
->
bv_val
,
STRERROR
(
save_errno
),
0
);
rc
=
LDAP_OTHER
;
if
(
rs
!=
NULL
)
rs
->
sr_text
=
save_errno
!=
ENOENT
?
"internal error (bad directory)"
:
!
is_rootDSE
?
"internal error (missing directory)"
:
"internal error (database directory does not exist)"
;
}
while
(
1
)
{
struct
berval
fname
,
itmp
;
struct
dirent
*
dir
;
}
else
{
bvlist
*
ptr
;
struct
dirent
*
dir
;
int
save_errno
=
0
;
while
(
(
dir
=
readdir
(
dir_of_path
))
!=
NULL
)
{
size_t
fname_len
;
bvlist
*
bvl
,
**
prev
;
char
*
trunc
,
*
idxp
,
*
endp
,
*
endp2
;
dir
=
readdir
(
dir_of_path
);
if
(
dir
==
NULL
)
break
;
/* end of the directory */
fname
.
bv_len
=
strlen
(
dir
->
d_name
);
if
(
fname
.
bv_len
<=
STRLENOF
(
LDIF
))
fname_len
=
strlen
(
dir
->
d_name
);
if
(
fname_len
<
STRLENOF
(
"x="
LDIF
))
/* min filename size */
continue
;
if
(
strcmp
(
dir
->
d_name
+
(
fname
.
bv
_len
-
STRLENOF
(
LDIF
)
)
,
LDIF
))
if
(
strcmp
(
dir
->
d_name
+
fname_len
-
STRLENOF
(
LDIF
),
LDIF
))
continue
;
fname
.
bv_val
=
dir
->
d_name
;
bvl
=
ch_malloc
(
sizeof
(
bvlist
)
);
ber_dupbv
(
&
bvl
->
bv
,
&
fname
);
BER_BVZERO
(
&
bvl
->
num
);
itmp
.
bv_val
=
ber_bvchr
(
&
bvl
->
bv
,
IX_FSL
);
if
(
itmp
.
bv_val
)
{
char
*
ptr
;
itmp
.
bv_val
++
;
itmp
.
bv_len
=
bvl
->
bv
.
bv_len
-
(
itmp
.
bv_val
-
bvl
->
bv
.
bv_val
);
ptr
=
ber_bvchr
(
&
itmp
,
IX_FSR
);
if
(
ptr
)
{
itmp
.
bv_len
=
ptr
-
itmp
.
bv_val
;
ber_dupbv
(
&
bvl
->
num
,
&
itmp
);
bvl
->
inum
=
strtol
(
itmp
.
bv_val
,
NULL
,
0
);
itmp
.
bv_val
[
0
]
=
'\0'
;
bvl
->
off
=
itmp
.
bv_val
-
bvl
->
bv
.
bv_val
;
if
(
*
fname_maxlenp
<
fname_len
)
*
fname_maxlenp
=
fname_len
;
bvl
=
SLAP_MALLOC
(
BVL_SIZE
(
fname_len
)
);
if
(
bvl
==
NULL
)
{
rc
=
LDAP_OTHER
;
save_errno
=
errno
;
break
;
}
strcpy
(
BVL_NAME
(
bvl
),
dir
->
d_name
);
/* Make it sortable by ("attr=val" or <preceding {num}, num>) */
trunc
=
BVL_NAME
(
bvl
)
+
fname_len
-
STRLENOF
(
LDIF
);
if
(
(
idxp
=
strchr
(
BVL_NAME
(
bvl
)
+
2
,
IX_FSL
))
!=
NULL
&&
(
endp
=
strchr
(
++
idxp
,
IX_FSR
))
!=
NULL
&&
endp
>
idxp
&&
(
eq_unsafe
||
idxp
[
-
2
]
==
'='
||
endp
+
1
==
trunc
)
)
{
/* attr={n}val or bconfig.c's "pseudo-indexed" attr=val{n} */
bvl
->
inum
=
strtol
(
idxp
,
&
endp2
,
10
);
if
(
endp2
==
endp
)
{
trunc
=
idxp
;
goto
truncate
;
}
}
for
(
prev
=
&
list
;
(
ptr
=
*
prev
)
!=
NULL
;
prev
=
&
ptr
->
next
)
{
int
cmp
=
strcmp
(
bvl
->
bv
.
bv_val
,
ptr
->
bv
.
bv_val
);
if
(
!
cmp
&&
bvl
->
num
.
bv_val
)
cmp
=
bvl
->
inum
-
ptr
->
inum
;
if
(
cmp
<
0
)
bvl
->
inum
=
INT_MIN
;
truncate:
bvl
->
trunc
=
trunc
;
bvl
->
savech
=
*
trunc
;
*
trunc
=
'\0'
;
for
(
prev
=
listp
;
(
ptr
=
*
prev
)
!=
NULL
;
prev
=
&
ptr
->
next
)
{
int
cmp
=
strcmp
(
BVL_NAME
(
bvl
),
BVL_NAME
(
ptr
));
if
(
cmp
<
0
||
(
cmp
==
0
&&
bvl
->
inum
<
ptr
->
inum
)
)
break
;
}
*
prev
=
bvl
;
bvl
->
next
=
ptr
;
}
closedir
(
dir_of_path
);
if
(
ck
->
op
->
ors_scope
==
LDAP_SCOPE_ONELEVEL
)
ck
->
op
->
ors_scope
=
LDAP_SCOPE_BASE
;
else
if
(
ck
->
op
->
ors_scope
==
LDAP_SCOPE_SUBORDINATE
)
ck
->
op
->
ors_scope
=
LDAP_SCOPE_SUBTREE
;
while
(
(
ptr
=
list
)
)
{
struct
berval
fpath
;
list
=
ptr
->
next
;
if
(
rc
==
LDAP_SUCCESS
)
{
if
(
ptr
->
num
.
bv_val
)
AC_MEMCPY
(
ptr
->
bv
.
bv_val
+
ptr
->
off
,
ptr
->
num
.
bv_val
,
ptr
->
num
.
bv_len
);
fullpath
(
path
,
&
ptr
->
bv
,
&
fpath
);
rc
=
r_enum_tree
(
ck
,
&
fpath
,
0
,
e
!=
NULL
?
&
e
->
e_name
:
pdn
,
e
!=
NULL
?
&
e
->
e_nname
:
pndn
);
free
(
fpath
.
bv_val
);
}
if
(
ptr
->
num
.
bv_val
)
free
(
ptr
->
num
.
bv_val
);
free
(
ptr
->
bv
.
bv_val
);
free
(
ptr
);
if
(
closedir
(
dir_of_path
)
<
0
)
{
save_errno
=
errno
;
rc
=
LDAP_OTHER
;
if
(
rs
!=
NULL
)
rs
->
sr_text
=
"internal error (bad directory)"
;
}
if
(
rc
!=
LDAP_SUCCESS
)
{
Debug
(
LDAP_DEBUG_ANY
,
"ldif_search_entry: %s
\"
%s
\"
: %s
\n
"
,
"error reading directory"
,
path
->
bv_val
,
STRERROR
(
save_errno
)
);
}
}
done:
if
(
fd
)
entry_free
(
e
);
return
rc
;
}
/*
* Send an entry, recursively search its children, and free or save it.
* Return an LDAP result code. Parameters:
* op, rs operation and reply. rs == NULL for slap tools.
* e entry to search, or NULL for rootDSE.
* scope scope for the part of the search from this entry.
* path LDIF filename -- bv_len and non-directory part are overwritten.
*/
static
int
enum_tree
(
enumCookie
*
ck
)
ldif_search_entry
(
Operation
*
op
,
SlapReply
*
rs
,
Entry
*
e
,
int
scope
,
struct
berval
*
path
)
{
int
rc
=
LDAP_SUCCESS
;
struct
berval
dn
=
BER_BVC
(
""
),
ndn
=
BER_BVC
(
""
);
if
(
scope
!=
LDAP_SCOPE_BASE
&&
e
!=
NULL
)
{
/* Copy DN/NDN since we send the entry with REP_ENTRY_MODIFIABLE,
* which bconfig.c seems to need. (TODO: see config_rename_one.)
*/
if
(
ber_dupbv
(
&
dn
,
&
e
->
e_name
)
==
NULL
||
ber_dupbv
(
&
ndn
,
&
e
->
e_nname
)
==
NULL
)
{
Debug
(
LDAP_DEBUG_ANY
,
"ldif_search_entry: out of memory
\n
"
,
0
,
0
,
0
);
rc
=
LDAP_OTHER
;
goto
done
;
}
}
/* Send the entry if appropriate, and free or save it */
if
(
e
!=
NULL
)
rc
=
ldif_send_entry
(
op
,
rs
,
e
,
scope
);
/* Search the children */
if
(
scope
!=
LDAP_SCOPE_BASE
&&
rc
==
LDAP_SUCCESS
)
{
bvlist
*
list
,
*
ptr
;
struct
berval
fpath
;
/* becomes child pathname */
char
*
dir_end
;
/* will point past dirname in fpath */
ldif2dir_len
(
*
path
);
ldif2dir_name
(
*
path
);
rc
=
ldif_readdir
(
op
,
rs
,
path
,
&
list
,
&
fpath
.
bv_len
);
if
(
list
!=
NULL
)
{
const
char
**
text
=
rs
==
NULL
?
NULL
:
&
rs
->
sr_text
;
if
(
scope
==
LDAP_SCOPE_ONELEVEL
)
scope
=
LDAP_SCOPE_BASE
;
else
if
(
scope
==
LDAP_SCOPE_SUBORDINATE
)
scope
=
LDAP_SCOPE_SUBTREE
;
/* Allocate fpath and fill in directory part */
dir_end
=
fullpath_alloc
(
&
fpath
,
path
,
fpath
.
bv_len
);
if
(
dir_end
==
NULL
)
rc
=
LDAP_OTHER
;
do
{
ptr
=
list
;
if
(
rc
==
LDAP_SUCCESS
)
{
*
ptr
->
trunc
=
ptr
->
savech
;
FILL_PATH
(
&
fpath
,
dir_end
,
BVL_NAME
(
ptr
));
rc
=
ldif_read_entry
(
op
,
fpath
.
bv_val
,
&
dn
,
&
ndn
,
&
e
,
text
);
switch
(
rc
)
{
case
LDAP_SUCCESS
:
rc
=
ldif_search_entry
(
op
,
rs
,
e
,
scope
,
&
fpath
);
break
;
case
LDAP_NO_SUCH_OBJECT
:
/* Only the search baseDN may produce noSuchObject. */
rc
=
LDAP_OTHER
;
if
(
rs
!=
NULL
)
rs
->
sr_text
=
"internal error "
"(did someone just remove an entry file?)"
;
Debug
(
LDAP_DEBUG_ANY
,
"ldif_search_entry: "
"file listed in parent directory does not exist: "
"
\"
%s
\"\n
"
,
fpath
.
bv_val
,
0
,
0
);
break
;
}
}
list
=
ptr
->
next
;
SLAP_FREE
(
ptr
);
}
while
(
list
!=
NULL
);
if
(
!
BER_BVISNULL
(
&
fpath
)
)
SLAP_FREE
(
fpath
.
bv_val
);
}
}
done:
if
(
!
BER_BVISEMPTY
(
&
dn
)
)
ber_memfree
(
dn
.
bv_val
);
if
(
!
BER_BVISEMPTY
(
&
ndn
)
)
ber_memfree
(
ndn
.
bv_val
);
return
rc
;
}
static
int
search_tree
(
Operation
*
op
,
SlapReply
*
rs
)
{
int
rc
=
LDAP_SUCCESS
;
Entry
*
e
=
NULL
;
struct
berval
path
;
struct
berval
pdn
,
pndn
;
int
rc
;
dnParent
(
&
ck
->
op
->
o_req_dn
,
&
pdn
);
dnParent
(
&
ck
->
op
->
o_req_ndn
,
&
pndn
);
dn2path
(
ck
->
op
->
o_bd
,
&
ck
->
op
->
o_req_ndn
,
&
path
);
rc
=
r_enum_tree
(
ck
,
&
path
,
BER_BVISEMPTY
(
&
ck
->
op
->
o_req_ndn
)
?
1
:
0
,
&
pdn
,
&
pndn
);
dn2path
(
op
->
o_bd
,
&
op
->
o_req_ndn
,
&
path
);
if
(
!
BER_BVISEMPTY
(
&
op
->
o_req_ndn
)
)
{
/* Read baseObject */
dnParent
(
&
op
->
o_req_dn
,
&
pdn
);
dnParent
(
&
op
->
o_req_ndn
,
&
pndn
);
rc
=
ldif_read_entry
(
op
,
path
.
bv_val
,
&
pdn
,
&
pndn
,
&
e
,
rs
==
NULL
?
NULL
:
&
rs
->
sr_text
);
}
if
(
rc
==
LDAP_SUCCESS
)
rc
=
ldif_search_entry
(
op
,
rs
,
e
,
op
->
ors_scope
,
&
path
);
ch_free
(
path
.
bv_val
);
return
rc
;
}
/* Get the parent directory path, plus the LDIF suffix overwritten by a \0 */
static
void
get_parent_path
(
struct
berval
*
dnpath
,
struct
berval
*
res
)
/*
* Prepare to create or rename an entry:
* Check that the entry does not already exist.
* Check that the parent entry exists and can have subordinates,
* unless need_dir is NULL or adding the suffix entry.
*
* Return an LDAP result code. May set *text to a message on failure.
* If success, set *dnpath to LDIF entry path and *need_dir to
* (directory must be created ? dirname : NULL).
*/
static
int
ldif_prepare_create
(
Operation
*
op
,
Entry
*
e
,
struct
berval
*
dnpath
,
char
**
need_dir
,
const
char
**
text
)
{
int
dnpathlen
=
dnpath
->
bv_len
;
int
i
;
for
(
i
=
dnpathlen
;
i
>
0
;
i
--
)
/* find the first path seperator */
if
(
dnpath
->
bv_val
[
i
]
==
LDAP_DIRSEP
[
0
])
BackendDB
*
be
=
op
->
o_bd
;
struct
ldif_info
*
li
=
(
struct
ldif_info
*
)
be
->
be_private
;
struct
berval
*
ndn
=
&
e
->
e_nname
;
struct
berval
ppath
=
BER_BVNULL
;
struct
stat
st
;
Entry
*
parent
=
NULL
;
int
rc
=
LDAP_SUCCESS
;
if
(
op
->
o_abandon
)
return
SLAPD_ABANDON
;
dn2path
(
be
,
ndn
,
dnpath
);
if
(
stat
(
dnpath
->
bv_val
,
&
st
)
==
0
)
{
/* entry .ldif file */
rc
=
LDAP_ALREADY_EXISTS
;
}
else
if
(
errno
!=
ENOENT
)
{
Debug
(
LDAP_DEBUG_ANY
,
"ldif_prepare_create: cannot stat
\"
%s
\"
: %s
\n
"
,
dnpath
->
bv_val
,
STRERROR
(
errno
),
0
);
rc
=
LDAP_OTHER
;
*
text
=
"internal error (cannot check entry file)"
;
}
else
if
(
need_dir
!=
NULL
)
{
*
need_dir
=
NULL
;
rc
=
get_parent_path
(
dnpath
,
&
ppath
);
/* If parent dir exists, so does parent .ldif:
* The directory gets created after and removed before the .ldif.
* Except with the database directory, which has no matching entry.
*/
if
(
rc
==
LDAP_SUCCESS
&&
stat
(
ppath
.
bv_val
,
&
st
)
<
0
)
{
rc
=
errno
==
ENOENT
&&
ppath
.
bv_len
>
li
->
li_base_path
.
bv_len
?
LDAP_NO_SUCH_OBJECT
:
LDAP_OTHER
;
}
switch
(
rc
)
{
case
LDAP_NO_SUCH_OBJECT
:
/* No parent dir, check parent .ldif */
dir2ldif_name
(
ppath
);
rc
=
ldif_read_entry
(
op
,
ppath
.
bv_val
,
NULL
,
NULL
,
(
op
->
o_tag
!=
LDAP_REQ_ADD
||
get_manageDSAit
(
op
)
?
&
parent
:
NULL
),
text
);
switch
(
rc
)
{
case
LDAP_SUCCESS
:
/* Check that parent is not a referral, unless
* ldif_back_referrals() already checked.
*/
if
(
parent
!=
NULL
)
{
int
is_ref
=
is_entry_referral
(
parent
);
entry_free
(
parent
);
if
(
is_ref
)
{
rc
=
LDAP_AFFECTS_MULTIPLE_DSAS
;
*
text
=
op
->
o_tag
==
LDAP_REQ_MODDN
?
"newSuperior is a referral object"
:
"parent is a referral object"
;
break
;
}
}
/* Must create parent directory. */
ldif2dir_name
(
ppath
);
*
need_dir
=
ppath
.
bv_val
;
break
;
case
LDAP_NO_SUCH_OBJECT
:
*
text
=
op
->
o_tag
==
LDAP_REQ_MODDN
?
"newSuperior object does not exist"
:
"parent does not exist"
;
break
;
}
break
;
res
->
bv_len
=
i
;
res
->
bv_val
=
ch_malloc
(
res
->
bv_len
+
1
+
STRLENOF
(
LDIF
)
);
strncpy
(
res
->
bv_val
,
dnpath
->
bv_val
,
i
);
strcpy
(
res
->
bv_val
+
i
,
LDIF
);
res
->
bv_val
[
i
]
=
'\0'
;
case
LDAP_OTHER
:
Debug
(
LDAP_DEBUG_ANY
,
"ldif_prepare_create: cannot stat
\"
%s
\"
parent dir: %s
\n
"
,
ndn
->
bv_val
,
STRERROR
(
errno
),
0
);
*
text
=
"internal error (cannot stat parent dir)"
;
break
;
}
if
(
*
need_dir
==
NULL
&&
ppath
.
bv_val
!=
NULL
)
SLAP_FREE
(
ppath
.
bv_val
);
}
if
(
rc
!=
LDAP_SUCCESS
)
{
SLAP_FREE
(
dnpath
->
bv_val
);
BER_BVZERO
(
dnpath
);
}
return
rc
;
}
static
int
apply_modify_to_entry
(
Entry
*
entry
,
Modifications
*
modlist
,
Operation
*
op
,
SlapReply
*
rs
)
static
int
apply_modify_to_entry
(
Entry
*
entry
,
Modifications
*
modlist
,
Operation
*
op
,
SlapReply
*
rs
)
{
char
textbuf
[
SLAP_TEXT_BUFLEN
];
int
rc
=
modlist
?
LDAP_UNWILLING_TO_PERFORM
:
LDAP_SUCCESS
;
...
...
@@ -695,14 +1022,14 @@ static int apply_modify_to_entry(Entry * entry,
&
rs
->
sr_text
,
textbuf
,
sizeof
(
textbuf
)
);
break
;
case
LDAP_MOD_DELETE
:
rc
=
modify_delete_values
(
entry
,
mods
,
get_permissiveModify
(
op
),
&
rs
->
sr_text
,
textbuf
,
sizeof
(
textbuf
)
);
break
;
case
LDAP_MOD_REPLACE
:
rc
=
modify_replace_values
(
entry
,
mods
,
get_permissiveModify
(
op
),
...
...
@@ -732,7 +1059,8 @@ static int apply_modify_to_entry(Entry * entry,
if
(
rc
!=
LDAP_SUCCESS
)
break
;
}
if
(
rc
==
LDAP_SUCCESS
)
{
if
(
rc
==
LDAP_SUCCESS
)
{
rs
->
sr_text
=
NULL
;
/* Needed at least with SLAP_MOD_SOFTADD */
if
(
is_oc
)
{
entry
->
e_ocflags
=
0
;
}
...
...
@@ -744,134 +1072,77 @@ static int apply_modify_to_entry(Entry * entry,
return
rc
;
}
int
static
int
ldif_back_referrals
(
Operation
*
op
,
SlapReply
*
rs
)
{
struct
ldif_info
*
li
=
NULL
;
Entry
*
entry
;
int
rc
=
LDAP_SUCCESS
;
#if 0
if ( op->o_tag == LDAP_REQ_SEARCH ) {
/* let search take care of itself */
return rc;
}
#endif
if
(
get_manageDSAit
(
op
)
)
{
/* let op take care of DSA management */
return
rc
;
}
struct
ldif_info
*
li
=
(
struct
ldif_info
*
)
op
->
o_bd
->
be_private
;
struct
berval
path
,
dn
=
op
->
o_req_dn
,
ndn
=
op
->
o_req_ndn
;
ber_len_t
min_dnlen
;
Entry
*
entry
=
NULL
,
**
entryp
;
BerVarray
ref
;
int
rc
;
if
(
BER_BVISEMPTY
(
&
op
->
o_req_ndn
)
)
{
/* the empty DN cannot be a referral */
return
rc
;
min_dnlen
=
op
->
o_bd
->
be_nsuffix
[
0
].
bv_len
;
if
(
min_dnlen
==
0
)
{
/* Catch root DSE (empty DN), it is not a referral */
min_dnlen
=
1
;
if
(
BER_BVISEMPTY
(
&
ndn
)
)
return
LDAP_SUCCESS
;
}
li
=
(
struct
ldif_info
*
)
op
->
o_bd
->
be_private
;
entryp
=
get_manageDSAit
(
op
)
?
NULL
:
&
entry
;
dn2path
(
op
->
o_bd
,
&
ndn
,
&
path
);
ldap_pvt_thread_rdwr_rlock
(
&
li
->
li_rdwr
);
get_entry
(
op
,
&
entry
,
NULL
);
/* no object is found for them */
if
(
entry
==
NULL
)
{
struct
berval
odn
=
op
->
o_req_dn
;
struct
berval
ondn
=
op
->
o_req_ndn
;
struct
berval
pndn
=
ondn
;
ber_len_t
min_dnlen
=
op
->
o_bd
->
be_nsuffix
[
0
].
bv_len
;
if
(
min_dnlen
==
0
)
min_dnlen
=
1
;
/* catch empty DN */
for
(
;
entry
==
NULL
;
)
{
dnParent
(
&
pndn
,
&
pndn
);
if
(
pndn
.
bv_len
<
min_dnlen
)
{
break
;
}
op
->
o_req_dn
=
pndn
;
op
->
o_req_ndn
=
pndn
;
get_entry
(
op
,
&
entry
,
NULL
);
}
for
(;;)
{
dnParent
(
&
dn
,
&
dn
);
dnParent
(
&
ndn
,
&
ndn
);
rc
=
ldif_read_entry
(
op
,
path
.
bv_val
,
&
dn
,
&
ndn
,
entryp
,
&
rs
->
sr_text
);
if
(
rc
!=
LDAP_NO_SUCH_OBJECT
)
break
;
ldap_pvt_thread_rdwr_runlock
(
&
li
->
li_rdwr
);
rc
=
LDAP_SUCCESS
;
if
(
ndn
.
bv_len
<
min_dnlen
)
break
;
(
void
)
get_parent_path
(
&
path
,
NULL
);
dir2ldif_name
(
path
);
entryp
=
&
entry
;
}
op
->
o_req_dn
=
odn
;
op
->
o_req_ndn
=
ondn
;
ldap_pvt_thread_rdwr_runlock
(
&
li
->
li_rdwr
)
;
SLAP_FREE
(
path
.
bv_val
)
;
rc
=
LDAP_SUCCESS
;
rs
->
sr_matched
=
NULL
;
if
(
entry
!=
NULL
)
{
if
(
entry
!=
NULL
)
{
if
(
is_entry_referral
(
entry
)
)
{
Debug
(
LDAP_DEBUG_TRACE
,
"ldif_back_referrals: tag=%lu target=
\"
%s
\"
matched=
\"
%s
\"\n
"
,
(
unsigned
long
)
op
->
o_tag
,
op
->
o_req_dn
.
bv_val
,
entry
->
e_name
.
bv_val
);
if
(
is_entry_referral
(
entry
)
)
{
(
unsigned
long
)
op
->
o_tag
,
op
->
o_req_dn
.
bv_val
,
entry
->
e_dn
);
ref
=
get_entry_referrals
(
op
,
entry
);
rs
->
sr_ref
=
referral_rewrite
(
ref
,
&
entry
->
e_name
,
&
op
->
o_req_dn
,
op
->
o_tag
==
LDAP_REQ_SEARCH
?
op
->
ors_scope
:
LDAP_SCOPE_DEFAULT
);
ber_bvarray_free
(
ref
);
if
(
rs
->
sr_ref
!=
NULL
)
{
/* send referral */
rc
=
rs
->
sr_err
=
LDAP_REFERRAL
;
rs
->
sr_matched
=
entry
->
e_dn
;
send_ldap_result
(
op
,
rs
);
ber_bvarray_free
(
rs
->
sr_ref
);
rs
->
sr_ref
=
NULL
;
}
else
{
rc
=
LDAP_OTHER
;
rs
->
sr_ref
=
get_entry_referrals
(
op
,
entry
);
if
(
rs
->
sr_ref
)
{
rs
->
sr_matched
=
ber_strdup_x
(
entry
->
e_name
.
bv_val
,
op
->
o_tmpmemctx
);
}
rs
->
sr_text
=
"bad referral object"
;
}
entry_free
(
entry
);
}
else
if
(
default_referral
!=
NULL
)
{
rc
=
LDAP_OTHER
;
rs
->
sr_ref
=
referral_rewrite
(
default_referral
,
NULL
,
&
op
->
o_req_dn
,
LDAP_SCOPE_DEFAULT
);
}
if
(
rs
->
sr_ref
!=
NULL
)
{
/* send referrals */
rc
=
rs
->
sr_err
=
LDAP_REFERRAL
;
send_ldap_result
(
op
,
rs
);
ber_bvarray_free
(
rs
->
sr_ref
);
rs
->
sr_ref
=
NULL
;
}
else
if
(
rc
!=
LDAP_SUCCESS
)
{
rs
->
sr_text
=
rs
->
sr_matched
?
"bad referral object"
:
NULL
;
}
if
(
rs
->
sr_matched
)
{
op
->
o_tmpfree
(
(
char
*
)
rs
->
sr_matched
,
op
->
o_tmpmemctx
);
rs
->
sr_matched
=
NULL
;
}
return
rc
;
}
ldap_pvt_thread_rdwr_runlock
(
&
li
->
li_rdwr
);
if
(
is_entry_referral
(
entry
)
)
{
/* entry is a referral */
BerVarray
refs
=
get_entry_referrals
(
op
,
entry
);
rs
->
sr_ref
=
referral_rewrite
(
refs
,
&
entry
->
e_name
,
&
op
->
o_req_dn
,
LDAP_SCOPE_DEFAULT
);
Debug
(
LDAP_DEBUG_TRACE
,
"ldif_back_referrals: tag=%lu target=
\"
%s
\"
matched=
\"
%s
\"\n
"
,
(
unsigned
long
)
op
->
o_tag
,
op
->
o_req_dn
.
bv_val
,
entry
->
e_name
.
bv_val
);
rs
->
sr_matched
=
entry
->
e_name
.
bv_val
;
if
(
rs
->
sr_ref
!=
NULL
)
{
rc
=
rs
->
sr_err
=
LDAP_REFERRAL
;
send_ldap_result
(
op
,
rs
);
ber_bvarray_free
(
rs
->
sr_ref
);
rs
->
sr_ref
=
NULL
;
}
else
{
rc
=
LDAP_OTHER
;
rs
->
sr_text
=
"bad referral object"
;
}
rs
->
sr_matched
=
NULL
;
ber_bvarray_free
(
refs
);
entry_free
(
entry
);
}
entry_free
(
entry
);
return
rc
;
}
...
...
@@ -885,7 +1156,7 @@ ldif_back_bind( Operation *op, SlapReply *rs )
Attribute
*
a
;
AttributeDescription
*
password
=
slap_schema
.
si_ad_userPassword
;
int
return_val
;
Entry
*
entry
;
Entry
*
entry
=
NULL
;
switch
(
be_rootdn_bind
(
op
,
rs
)
)
{
case
SLAP_CB_CONTINUE
:
...
...
@@ -899,7 +1170,7 @@ ldif_back_bind( Operation *op, SlapReply *rs )
li
=
(
struct
ldif_info
*
)
op
->
o_bd
->
be_private
;
ldap_pvt_thread_rdwr_rlock
(
&
li
->
li_rdwr
);
return_val
=
get_entry
(
op
,
&
entry
,
NULL
);
return_val
=
get_entry
(
op
,
&
entry
,
NULL
,
NULL
);
/* no object is found for them */
if
(
return_val
!=
LDAP_SUCCESS
)
{
...
...
@@ -923,150 +1194,115 @@ ldif_back_bind( Operation *op, SlapReply *rs )
}
/* let the front-end send success */
return_val
=
0
;
goto
return_result
;
return_val
=
LDAP_SUCCESS
;
return_result:
ldap_pvt_thread_rdwr_runlock
(
&
li
->
li_rdwr
);
if
(
return_val
!=
0
)
if
(
return_val
!=
LDAP_SUCCESS
)
send_ldap_result
(
op
,
rs
);
if
(
entry
!=
NULL
)
entry_free
(
entry
);
return
return_val
;
}
static
int
ldif_back_search
(
Operation
*
op
,
SlapReply
*
rs
)
static
int
ldif_back_search
(
Operation
*
op
,
SlapReply
*
rs
)
{
struct
ldif_info
*
li
=
(
struct
ldif_info
*
)
op
->
o_bd
->
be_private
;
enumCookie
ck
=
{
NULL
,
NULL
,
NULL
,
0
,
0
};
ck
.
op
=
op
;
ck
.
rs
=
rs
;
ldap_pvt_thread_rdwr_rlock
(
&
li
->
li_rdwr
);
rs
->
sr_err
=
enum
_tree
(
&
ck
);
rs
->
sr_err
=
search
_tree
(
op
,
rs
);
ldap_pvt_thread_rdwr_runlock
(
&
li
->
li_rdwr
);
send_ldap_result
(
op
,
rs
);
return
rs
->
sr_err
;
}
static
int
ldif_back_add
(
Operation
*
op
,
SlapReply
*
rs
)
{
static
int
ldif_back_add
(
Operation
*
op
,
SlapReply
*
rs
)
{
struct
ldif_info
*
li
=
(
struct
ldif_info
*
)
op
->
o_bd
->
be_private
;
Entry
*
e
=
op
->
ora_e
;
struct
berval
dn
=
e
->
e_nname
;
struct
berval
leaf_path
=
BER_BVNULL
;
struct
stat
stats
;
int
statres
;
struct
berval
path
;
char
*
parentdir
;
char
textbuf
[
SLAP_TEXT_BUFLEN
];
int
rc
;
Debug
(
LDAP_DEBUG_TRACE
,
"ldif_back_add:
\"
%s
\"\n
"
,
dn
.
bv_val
,
0
,
0
);
Debug
(
LDAP_DEBUG_TRACE
,
"ldif_back_add:
\"
%s
\"\n
"
,
e
->
e_dn
,
0
,
0
);
r
s
->
sr_err
=
entry_schema_check
(
op
,
e
,
NULL
,
0
,
1
,
r
c
=
entry_schema_check
(
op
,
e
,
NULL
,
0
,
1
,
&
rs
->
sr_text
,
textbuf
,
sizeof
(
textbuf
)
);
if
(
rs
->
sr_err
!=
LDAP_SUCCESS
)
goto
send_res
;
rs
->
sr_err
=
slap_add_opattrs
(
op
,
&
rs
->
sr_text
,
textbuf
,
sizeof
(
textbuf
),
1
);
if
(
rs
->
sr_err
!=
LDAP_SUCCESS
)
goto
send_res
;
if
(
rc
!=
LDAP_SUCCESS
)
goto
send_res
;
ldap_pvt_thread_rdwr_wlock
(
&
li
->
li_rdwr
);
rc
=
slap_add_opattrs
(
op
,
&
rs
->
sr_text
,
textbuf
,
sizeof
(
textbuf
),
1
);
if
(
rc
!=
LDAP_SUCCESS
)
goto
send_res
;
dn2path
(
op
->
o_bd
,
&
dn
,
&
leaf_path
);
ldap_pvt_thread_mutex_lock
(
&
li
->
li_modop_mutex
);
if
(
leaf_path
.
bv_val
!=
NULL
)
{
struct
berval
base
=
BER_BVNULL
;
/* build path to container and ldif of container */
get_parent_path
(
&
leaf_path
,
&
base
);
rc
=
ldif_prepare_create
(
op
,
e
,
&
path
,
&
parentdir
,
&
rs
->
sr_text
);
if
(
rc
==
LDAP_SUCCESS
)
{
ldap_pvt_thread_rdwr_wlock
(
&
li
->
li_rdwr
);
rc
=
ldif_write_entry
(
op
,
e
,
&
path
,
parentdir
,
&
rs
->
sr_text
);
ldap_pvt_thread_rdwr_wunlock
(
&
li
->
li_rdwr
);
statres
=
stat
(
base
.
bv_val
,
&
stats
);
/* check if container exists */
if
(
statres
==
-
1
&&
errno
==
ENOENT
)
{
/* container missing */
base
.
bv_val
[
base
.
bv_len
]
=
LDIF_FILETYPE_SEP
;
statres
=
stat
(
base
.
bv_val
,
&
stats
);
/* check for leaf node */
base
.
bv_val
[
base
.
bv_len
]
=
'\0'
;
if
(
statres
==
-
1
&&
errno
==
ENOENT
)
{
rs
->
sr_err
=
LDAP_NO_SUCH_OBJECT
;
/* parent doesn't exist */
rs
->
sr_text
=
"Parent does not exist"
;
}
else
if
(
statres
!=
-
1
)
{
/* create parent */
int
mkdirres
=
mkdir
(
base
.
bv_val
,
0750
);
if
(
mkdirres
==
-
1
)
{
rs
->
sr_err
=
LDAP_UNWILLING_TO_PERFORM
;
rs
->
sr_text
=
"Could not create parent folder"
;
Debug
(
LDAP_DEBUG_ANY
,
"could not create folder
\"
%s
\"
: %s
\n
"
,
base
.
bv_val
,
STRERROR
(
errno
),
0
);
}
}
else
rs
->
sr_err
=
LDAP_UNWILLING_TO_PERFORM
;
}
/* container was possibly created, move on to add the entry */
if
(
rs
->
sr_err
==
LDAP_SUCCESS
)
{
statres
=
stat
(
leaf_path
.
bv_val
,
&
stats
);
if
(
statres
==
-
1
&&
errno
==
ENOENT
)
{
rs
->
sr_err
=
spew_entry
(
e
,
&
leaf_path
,
1
,
NULL
);
}
else
if
(
statres
==
-
1
)
{
rs
->
sr_err
=
LDAP_UNWILLING_TO_PERFORM
;
Debug
(
LDAP_DEBUG_ANY
,
"could not stat file
\"
%s
\"
: %s
\n
"
,
leaf_path
.
bv_val
,
STRERROR
(
errno
),
0
);
}
else
/* it already exists */
rs
->
sr_err
=
LDAP_ALREADY_EXISTS
;
}
SLAP_FREE
(
base
.
bv_val
);
SLAP_FREE
(
leaf_path
.
bv_val
);
SLAP_FREE
(
path
.
bv_val
);
if
(
parentdir
!=
NULL
)
SLAP_FREE
(
parentdir
);
}
ldap_pvt_thread_
rdwr_w
unlock
(
&
li
->
li_
rdwr
);
ldap_pvt_thread_
mutex_
unlock
(
&
li
->
li_
modop_mutex
);
send_res:
Debug
(
LDAP_DEBUG_TRACE
,
"ldif_back_add: err: %d text: %s
\n
"
,
rs
->
sr_err
,
rs
->
sr_text
?
rs
->
sr_text
:
""
,
0
);
send_ldap_result
(
op
,
rs
);
send_res:
rs
->
sr_err
=
rc
;
Debug
(
LDAP_DEBUG_TRACE
,
"ldif_back_add: err: %d text: %s
\n
"
,
rc
,
rs
->
sr_text
?
rs
->
sr_text
:
""
,
0
);
send_ldap_result
(
op
,
rs
);
slap_graduate_commit_csn
(
op
);
return
rs
->
sr_err
;
}
static
int
ldif_back_modify
(
Operation
*
op
,
SlapReply
*
rs
)
{
static
int
ldif_back_modify
(
Operation
*
op
,
SlapReply
*
rs
)
{
struct
ldif_info
*
li
=
(
struct
ldif_info
*
)
op
->
o_bd
->
be_private
;
Modifications
*
modlst
=
op
->
orm_modlist
;
struct
berval
path
;
Entry
*
entry
;
int
spew_res
;
int
rc
;
slap_mods_opattrs
(
op
,
&
op
->
orm_modlist
,
1
);
ldap_pvt_thread_
rdwr_w
lock
(
&
li
->
li_
rdwr
);
ldap_pvt_thread_
mutex_
lock
(
&
li
->
li_
modop_mutex
);
rs
->
sr_err
=
get_entry
(
op
,
&
entry
,
&
path
);
if
(
entry
!=
NULL
)
{
rs
->
sr_err
=
apply_modify_to_entry
(
entry
,
modlst
,
op
,
rs
);
if
(
rs
->
sr_err
==
LDAP_SUCCESS
)
{
int
save_errno
;
spew_res
=
spew_entry
(
entry
,
&
path
,
1
,
&
save_errno
);
if
(
spew_res
==
-
1
)
{
Debug
(
LDAP_DEBUG_ANY
,
"%s ldif_back_modify: could not output entry
\"
%s
\"
: %s
\n
"
,
op
->
o_log_prefix
,
entry
->
e_name
.
bv_val
,
STRERROR
(
save_errno
)
);
rs
->
sr_err
=
LDAP_UNWILLING_TO_PERFORM
;
}
rc
=
get_entry
(
op
,
&
entry
,
&
path
,
&
rs
->
sr_text
);
if
(
rc
==
LDAP_SUCCESS
)
{
rc
=
apply_modify_to_entry
(
entry
,
modlst
,
op
,
rs
);
if
(
rc
==
LDAP_SUCCESS
)
{
ldap_pvt_thread_rdwr_wlock
(
&
li
->
li_rdwr
);
rc
=
ldif_write_entry
(
op
,
entry
,
&
path
,
NULL
,
&
rs
->
sr_text
);
ldap_pvt_thread_rdwr_wunlock
(
&
li
->
li_rdwr
);
}
entry_free
(
entry
);
SLAP_FREE
(
path
.
bv_val
);
}
rs
->
sr_text
=
NULL
;
ldap_pvt_thread_rdwr_wunlock
(
&
li
->
li_rdwr
);
send_ldap_result
(
op
,
rs
);
ldap_pvt_thread_mutex_unlock
(
&
li
->
li_modop_mutex
);
rs
->
sr_err
=
rc
;
send_ldap_result
(
op
,
rs
);
slap_graduate_commit_csn
(
op
);
return
rs
->
sr_err
;
}
static
int
ldif_back_delete
(
Operation
*
op
,
SlapReply
*
rs
)
{
static
int
ldif_back_delete
(
Operation
*
op
,
SlapReply
*
rs
)
{
struct
ldif_info
*
li
=
(
struct
ldif_info
*
)
op
->
o_bd
->
be_private
;
struct
berval
path
;
int
r
es
=
0
;
int
r
c
=
LDAP_SUCCESS
;
if
(
BER_BVISEMPTY
(
&
op
->
o_csn
))
{
struct
berval
csn
;
...
...
@@ -1077,48 +1313,53 @@ static int ldif_back_delete(Operation *op, SlapReply *rs) {
slap_get_csn
(
op
,
&
csn
,
1
);
}
ldap_pvt_thread_rdwr_wlock
(
&
li
->
li_rdwr
);
ldap_pvt_thread_mutex_lock
(
&
li
->
li_modop_mutex
);
ldap_pvt_thread_rdwr_wlock
(
&
li
->
li_rdwr
);
if
(
op
->
o_abandon
)
{
rc
=
SLAPD_ABANDON
;
goto
done
;
}
dn2path
(
op
->
o_bd
,
&
op
->
o_req_ndn
,
&
path
);
path
.
bv_val
[
path
.
bv_len
-
STRLENOF
(
LDIF
)]
=
'\0'
;
res
=
rmdir
(
path
.
bv_val
);
path
.
bv_val
[
path
.
bv_len
-
STRLENOF
(
LDIF
)]
=
LDIF_FILETYPE_SEP
;
rs
->
sr_err
=
LDAP_SUCCESS
;
if
(
res
)
{
ldif2dir_len
(
path
);
ldif2dir_name
(
path
);
if
(
rmdir
(
path
.
bv_val
)
<
0
)
{
switch
(
errno
)
{
case
ENOTEMPTY
:
r
s
->
sr_err
=
LDAP_NOT_ALLOWED_ON_NONLEAF
;
r
c
=
LDAP_NOT_ALLOWED_ON_NONLEAF
;
break
;
case
ENOENT
:
/* is leaf, go on */
res
=
0
;
break
;
default:
rs
->
sr_err
=
LDAP_UNWILLING_TO_PERFORM
;
rc
=
LDAP_OTHER
;
rs
->
sr_text
=
"internal error (cannot delete subtree directory)"
;
break
;
}
}
if
(
!
res
)
{
res
=
unlink
(
path
.
bv_val
);
if
(
res
==
-
1
)
{
switch
(
errno
)
{
case
ENOENT
:
rs
->
sr_err
=
LDAP_NO_SUCH_OBJECT
;
break
;
default:
rs
->
sr_err
=
LDAP_UNWILLING_TO_PERFORM
;
break
;
if
(
rc
==
LDAP_SUCCESS
)
{
dir2ldif_name
(
path
);
if
(
unlink
(
path
.
bv_val
)
<
0
)
{
rc
=
LDAP_NO_SUCH_OBJECT
;
if
(
errno
!=
ENOENT
)
{
rc
=
LDAP_OTHER
;
rs
->
sr_text
=
"internal error (cannot delete entry file)"
;
}
}
}
SLAP_FREE
(
path
.
bv_val
);
ldap_pvt_thread_rdwr_wunlock
(
&
li
->
li_rdwr
);
send_ldap_result
(
op
,
rs
);
if
(
rc
==
LDAP_OTHER
)
{
Debug
(
LDAP_DEBUG_ANY
,
"ldif_back_delete: %s
\"
%s
\"
: %s
\n
"
,
"cannot delete"
,
path
.
bv_val
,
STRERROR
(
errno
)
);
}
SLAP_FREE
(
path
.
bv_val
);
done:
ldap_pvt_thread_rdwr_wunlock
(
&
li
->
li_rdwr
);
ldap_pvt_thread_mutex_unlock
(
&
li
->
li_modop_mutex
);
rs
->
sr_err
=
rc
;
send_ldap_result
(
op
,
rs
);
slap_graduate_commit_csn
(
op
);
return
rs
->
sr_err
;
}
...
...
@@ -1128,94 +1369,109 @@ static int
ldif_move_entry
(
Operation
*
op
,
Entry
*
entry
,
struct
berval
*
oldpath
)
int
same_ndn
,
struct
berval
*
oldpath
,
const
char
**
text
)
{
int
res
;
int
exists_res
;
struct
ldif_info
*
li
=
(
struct
ldif_info
*
)
op
->
o_bd
->
be_private
;
struct
berval
newpath
;
char
*
parentdir
=
NULL
,
*
trash
;
int
rc
,
rename_res
;
dn2path
(
op
->
o_bd
,
&
entry
->
e_nname
,
&
newpath
);
if
((
entry
==
NULL
||
oldpath
->
bv_val
==
NULL
)
||
newpath
.
bv_val
==
NULL
)
{
/* some object doesn't exist */
res
=
LDAP_NO_SUCH_OBJECT
;
if
(
same_ndn
)
{
rc
=
LDAP_SUCCESS
;
newpath
=
*
oldpath
;
}
else
{
rc
=
ldif_prepare_create
(
op
,
entry
,
&
newpath
,
op
->
orr_newSup
?
&
parentdir
:
NULL
,
text
);
}
else
{
/* do the modrdn */
exists_res
=
open
(
newpath
.
bv_val
,
O_RDONLY
);
if
(
exists_res
==
-
1
&&
errno
==
ENOENT
)
{
ldap_pvt_thread_mutex_lock
(
&
entry2str_mutex
);
res
=
spew_entry
(
entry
,
&
newpath
,
0
,
NULL
);
if
(
res
!=
-
1
)
{
/* if this fails we should log something bad */
res
=
unlink
(
oldpath
->
bv_val
);
oldpath
->
bv_val
[
oldpath
->
bv_len
-
STRLENOF
(
".ldif"
)]
=
'\0'
;
newpath
.
bv_val
[
newpath
.
bv_len
-
STRLENOF
(
".ldif"
)]
=
'\0'
;
res
=
rename
(
oldpath
->
bv_val
,
newpath
.
bv_val
);
res
=
LDAP_SUCCESS
;
if
(
rc
==
LDAP_SUCCESS
)
{
ldap_pvt_thread_rdwr_wlock
(
&
li
->
li_rdwr
);
rc
=
ldif_write_entry
(
op
,
entry
,
&
newpath
,
parentdir
,
text
);
if
(
rc
==
LDAP_SUCCESS
&&
!
same_ndn
)
{
trash
=
oldpath
->
bv_val
;
/* will be .ldif file to delete */
ldif2dir_len
(
newpath
);
ldif2dir_len
(
*
oldpath
);
/* Move subdir before deleting old entry,
* so .ldif always exists if subdir does.
*/
ldif2dir_name
(
newpath
);
ldif2dir_name
(
*
oldpath
);
rename_res
=
move_dir
(
oldpath
->
bv_val
,
newpath
.
bv_val
);
if
(
rename_res
!=
0
&&
errno
!=
ENOENT
)
{
rc
=
LDAP_OTHER
;
*
text
=
"internal error (cannot move this subtree)"
;
trash
=
newpath
.
bv_val
;
}
else
{
if
(
errno
==
ENOENT
)
res
=
LDAP_NO_SUCH_OBJECT
;
else
res
=
LDAP_UNWILLING_TO_PERFORM
;
unlink
(
newpath
.
bv_val
);
/* in case file was created */
/* Delete old entry, or if error undo change */
for
(;;)
{
dir2ldif_name
(
newpath
);
dir2ldif_name
(
*
oldpath
);
if
(
unlink
(
trash
)
==
0
)
break
;
if
(
rc
==
LDAP_SUCCESS
)
{
/* Prepare to undo change and return failure */
rc
=
LDAP_OTHER
;
*
text
=
"internal error (cannot move this entry)"
;
trash
=
newpath
.
bv_val
;
if
(
rename_res
!=
0
)
continue
;
/* First move subdirectory back */
ldif2dir_name
(
newpath
);
ldif2dir_name
(
*
oldpath
);
if
(
move_dir
(
newpath
.
bv_val
,
oldpath
->
bv_val
)
==
0
)
continue
;
}
*
text
=
"added new but couldn't delete old entry!"
;
break
;
}
ldap_pvt_thread_mutex_unlock
(
&
entry2str_mutex
);
}
else
if
(
exists_res
)
{
int
close_res
=
close
(
exists_res
);
res
=
LDAP_ALREADY_EXISTS
;
if
(
close_res
==
-
1
)
{
/* log heinous error */
if
(
rc
!=
LDAP_SUCCESS
)
{
char
s
[
128
];
snprintf
(
s
,
sizeof
s
,
"%s (%s)"
,
*
text
,
STRERROR
(
errno
)
);
Debug
(
LDAP_DEBUG_ANY
,
"ldif_move_entry: %s:
\"
%s
\"
->
\"
%s
\"\n
"
,
s
,
op
->
o_req_dn
.
bv_val
,
entry
->
e_dn
);
}
}
else
{
res
=
LDAP_UNWILLING_TO_PERFORM
;
}
ldap_pvt_thread_rdwr_wunlock
(
&
li
->
li_rdwr
);
if
(
!
same_ndn
)
SLAP_FREE
(
newpath
.
bv_val
);
if
(
parentdir
!=
NULL
)
SLAP_FREE
(
parentdir
);
}
if
(
newpath
.
bv_val
!=
NULL
)
SLAP_FREE
(
newpath
.
bv_val
);
return
res
;
return
rc
;
}
static
int
ldif_back_modrdn
(
Operation
*
op
,
SlapReply
*
rs
)
ldif_back_modrdn
(
Operation
*
op
,
SlapReply
*
rs
)
{
struct
ldif_info
*
li
=
(
struct
ldif_info
*
)
op
->
o_bd
->
be_private
;
struct
berval
new_dn
=
BER_BVNULL
,
new_ndn
=
BER_BVNULL
;
struct
berval
p_dn
,
old_path
;
Entry
*
entry
;
int
rc
;
int
rc
,
same_ndn
;
slap_mods_opattrs
(
op
,
&
op
->
orr_modlist
,
1
);
ldap_pvt_thread_
rdwr_w
lock
(
&
li
->
li_
rdwr
);
ldap_pvt_thread_
mutex_
lock
(
&
li
->
li_
modop_mutex
);
rc
=
get_entry
(
op
,
&
entry
,
&
old_path
);
rc
=
get_entry
(
op
,
&
entry
,
&
old_path
,
&
rs
->
sr_text
);
if
(
rc
==
LDAP_SUCCESS
)
{
/* build new dn, and new ndn for the entry */
if
(
op
->
oq_modrdn
.
rs_newSup
!=
NULL
)
{
struct
berval
op_dn
=
op
->
o_req_dn
,
op_ndn
=
op
->
o_req_ndn
;
Entry
*
np
;
/* new superior */
p_dn
=
*
op
->
oq_modrdn
.
rs_newSup
;
op
->
o_req_dn
=
*
op
->
oq_modrdn
.
rs_newSup
;
op
->
o_req_ndn
=
*
op
->
oq_modrdn
.
rs_nnewSup
;
rc
=
get_entry
(
op
,
&
np
,
NULL
);
op
->
o_req_dn
=
op_dn
;
op
->
o_req_ndn
=
op_ndn
;
if
(
rc
!=
LDAP_SUCCESS
)
{
goto
no_such_object
;
}
entry_free
(
np
);
}
else
{
dnParent
(
&
entry
->
e_name
,
&
p_dn
);
}
build_new_dn
(
&
new_dn
,
&
p_dn
,
&
op
->
oq_modrdn
.
rs_newrdn
,
NULL
);
build_new_dn
(
&
new_dn
,
&
p_dn
,
&
op
->
oq_modrdn
.
rs_newrdn
,
NULL
);
dnNormalize
(
0
,
NULL
,
NULL
,
&
new_dn
,
&
new_ndn
,
NULL
);
same_ndn
=
!
ber_bvcmp
(
&
entry
->
e_nname
,
&
new_ndn
);
ber_memfree_x
(
entry
->
e_name
.
bv_val
,
NULL
);
ber_memfree_x
(
entry
->
e_nname
.
bv_val
,
NULL
);
entry
->
e_name
=
new_dn
;
...
...
@@ -1224,15 +1480,14 @@ ldif_back_modrdn(Operation *op, SlapReply *rs)
/* perform the modifications */
rc
=
apply_modify_to_entry
(
entry
,
op
->
orr_modlist
,
op
,
rs
);
if
(
rc
==
LDAP_SUCCESS
)
rc
=
ldif_move_entry
(
op
,
entry
,
&
old_path
);
rc
=
ldif_move_entry
(
op
,
entry
,
same_ndn
,
&
old_path
,
&
rs
->
sr_text
);
no_such_object:
;
entry_free
(
entry
);
SLAP_FREE
(
old_path
.
bv_val
);
}
rs
->
sr_text
=
""
;
ldap_pvt_thread_rdwr_wunlock
(
&
li
->
li_rdwr
);
ldap_pvt_thread_mutex_unlock
(
&
li
->
li_modop_mutex
);
rs
->
sr_err
=
rc
;
send_ldap_result
(
op
,
rs
);
slap_graduate_commit_csn
(
op
);
...
...
@@ -1260,7 +1515,7 @@ ldif_back_entry_get(
ldap_pvt_thread_rdwr_rlock
(
&
li
->
li_rdwr
);
op
->
o_req_dn
=
*
ndn
;
op
->
o_req_ndn
=
*
ndn
;
rc
=
get_entry
(
op
,
e
,
NULL
);
rc
=
get_entry
(
op
,
e
,
NULL
,
NULL
);
op
->
o_req_dn
=
op_dn
;
op
->
o_req_ndn
=
op_ndn
;
ldap_pvt_thread_rdwr_runlock
(
&
li
->
li_rdwr
);
...
...
@@ -1277,107 +1532,102 @@ ldif_back_entry_get(
/* Slap tools */
static
int
ldif_tool_entry_open
(
BackendDB
*
be
,
int
mode
)
{
struct
ldif_info
*
li
=
(
struct
ldif_info
*
)
be
->
be_private
;
li
->
li_tool_current
=
0
;
return
0
;
}
static
int
ldif_tool_entry_open
(
BackendDB
*
be
,
int
mode
)
{
struct
ldif_tool
*
tl
=
&
((
struct
ldif_info
*
)
be
->
be_private
)
->
li_tool
;
static
int
ldif_tool_entry_close
(
BackendDB
*
be
)
{
struct
ldif_info
*
li
=
(
struct
ldif_info
*
)
be
->
be_private
;
tl
->
ecurrent
=
0
;
return
0
;
}
SLAP_FREE
(
li
->
li_tool_cookie
.
entries
);
static
int
ldif_tool_entry_close
(
BackendDB
*
be
)
{
struct
ldif_tool
*
tl
=
&
((
struct
ldif_info
*
)
be
->
be_private
)
->
li_tool
;
Entry
**
entries
=
tl
->
entries
;
ID
i
;
for
(
i
=
tl
->
ecount
;
i
--
;
)
if
(
entries
[
i
]
)
entry_free
(
entries
[
i
]
);
SLAP_FREE
(
entries
);
tl
->
entries
=
NULL
;
tl
->
ecount
=
tl
->
elen
=
0
;
return
0
;
}
static
ID
ldif_tool_entry_next
(
BackendDB
*
be
)
static
ID
ldif_tool_entry_next
(
BackendDB
*
be
)
{
struct
ldif_info
*
li
=
(
struct
ldif_info
*
)
be
->
be_private
;
if
(
li
->
li_tool_current
>=
li
->
li_tool_cookie
.
eind
)
struct
ldif_tool
*
tl
=
&
((
struct
ldif_info
*
)
be
->
be_private
)
->
li_tool
;
if
(
tl
->
ecurrent
>=
tl
->
ecount
)
return
NOID
;
else
return
++
li
->
li_tool_
current
;
return
++
tl
->
e
current
;
}
static
ID
ldif_tool_entry_first
(
BackendDB
*
be
)
ldif_tool_entry_first
(
BackendDB
*
be
)
{
struct
ldif_
info
*
li
=
(
struct
ldif_info
*
)
be
->
be_private
;
struct
ldif_
tool
*
tl
=
&
(
(
struct
ldif_info
*
)
be
->
be_private
)
->
li_tool
;
if
(
li
->
li_tool_cookie
.
entries
==
NULL
)
{
if
(
tl
->
entries
==
NULL
)
{
Operation
op
=
{
0
};
op
.
o_bd
=
be
;
op
.
o_req_dn
=
*
be
->
be_suffix
;
op
.
o_req_ndn
=
*
be
->
be_nsuffix
;
op
.
ors_scope
=
LDAP_SCOPE_SUBTREE
;
li
->
li_tool_cookie
.
op
=
&
op
;
(
void
)
enum_tree
(
&
li
->
li_tool_cookie
);
li
->
li_tool_cookie
.
op
=
NULL
;
if
(
search_tree
(
&
op
,
NULL
)
!=
LDAP_SUCCESS
)
{
tl
->
ecurrent
=
tl
->
ecount
;
/* fail ldif_tool_entry_next() */
return
0
;
/* fail ldif_tool_entry_get() */
}
}
return
ldif_tool_entry_next
(
be
);
}
static
Entry
*
ldif_tool_entry_get
(
BackendDB
*
be
,
ID
id
)
{
struct
ldif_info
*
li
=
(
struct
ldif_info
*
)
be
->
be_private
;
Entry
*
e
;
if
(
id
>
li
->
li_tool_cookie
.
eind
||
id
<
1
)
return
NULL
;
else
{
e
=
li
->
li_tool_cookie
.
entries
[
id
-
1
];
li
->
li_tool_cookie
.
entries
[
id
-
1
]
=
NULL
;
return
e
;
static
Entry
*
ldif_tool_entry_get
(
BackendDB
*
be
,
ID
id
)
{
struct
ldif_tool
*
tl
=
&
((
struct
ldif_info
*
)
be
->
be_private
)
->
li_tool
;
Entry
*
e
=
NULL
;
--
id
;
if
(
id
<
tl
->
ecount
)
{
e
=
tl
->
entries
[
id
]
;
tl
->
entries
[
id
]
=
NULL
;
}
return
e
;
}
static
ID
ldif_tool_entry_put
(
BackendDB
*
be
,
Entry
*
e
,
struct
berval
*
text
)
{
struct
berval
leaf_path
=
BER_BVNULL
;
struct
stat
stats
;
int
statres
;
int
res
=
LDAP_SUCCESS
;
dn2path
(
be
,
&
e
->
e_nname
,
&
leaf_path
);
if
(
leaf_path
.
bv_val
!=
NULL
)
{
struct
berval
base
=
BER_BVNULL
;
/* build path to container, and path to ldif of container */
get_parent_path
(
&
leaf_path
,
&
base
);
statres
=
stat
(
base
.
bv_val
,
&
stats
);
/* check if container exists */
if
(
statres
==
-
1
&&
errno
==
ENOENT
)
{
/* container missing */
base
.
bv_val
[
base
.
bv_len
]
=
LDIF_FILETYPE_SEP
;
statres
=
stat
(
base
.
bv_val
,
&
stats
);
/* check for leaf node */
base
.
bv_val
[
base
.
bv_len
]
=
'\0'
;
if
(
statres
==
-
1
&&
errno
==
ENOENT
)
{
res
=
LDAP_NO_SUCH_OBJECT
;
/* parent doesn't exist */
}
else
if
(
statres
!=
-
1
)
{
/* create parent */
int
mkdirres
=
mkdir
(
base
.
bv_val
,
0750
);
if
(
mkdirres
==
-
1
)
{
res
=
LDAP_UNWILLING_TO_PERFORM
;
}
}
else
res
=
LDAP_UNWILLING_TO_PERFORM
;
}
/* container was possibly created, move on to add the entry */
if
(
res
==
LDAP_SUCCESS
)
{
statres
=
stat
(
leaf_path
.
bv_val
,
&
stats
);
if
(
statres
==
-
1
&&
errno
==
ENOENT
)
{
res
=
spew_entry
(
e
,
&
leaf_path
,
0
,
NULL
);
}
else
/* it already exists */
res
=
LDAP_ALREADY_EXISTS
;
}
SLAP_FREE
(
base
.
bv_val
);
SLAP_FREE
(
leaf_path
.
bv_val
);
}
static
ID
ldif_tool_entry_put
(
BackendDB
*
be
,
Entry
*
e
,
struct
berval
*
text
)
{
int
rc
;
const
char
*
errmsg
=
NULL
;
struct
berval
path
;
char
*
parentdir
;
Operation
op
=
{
0
};
if
(
res
==
LDAP_SUCCESS
)
{
return
1
;
op
.
o_bd
=
be
;
rc
=
ldif_prepare_create
(
&
op
,
e
,
&
path
,
&
parentdir
,
&
errmsg
);
if
(
rc
==
LDAP_SUCCESS
)
{
rc
=
ldif_write_entry
(
&
op
,
e
,
&
path
,
parentdir
,
&
errmsg
);
SLAP_FREE
(
path
.
bv_val
);
if
(
parentdir
!=
NULL
)
SLAP_FREE
(
parentdir
);
if
(
rc
==
LDAP_SUCCESS
)
return
1
;
}
else
return
NOID
;
if
(
errmsg
==
NULL
&&
rc
!=
LDAP_OTHER
)
errmsg
=
ldap_err2string
(
rc
);
if
(
errmsg
!=
NULL
)
snprintf
(
text
->
bv_val
,
text
->
bv_len
,
"%s"
,
errmsg
);
return
NOID
;
}
...
...
@@ -1391,7 +1641,8 @@ ldif_back_db_init( BackendDB *be, ConfigReply *cr )
li
=
ch_calloc
(
1
,
sizeof
(
struct
ldif_info
)
);
be
->
be_private
=
li
;
be
->
be_cf_ocs
=
ldifocs
;
ldap_pvt_thread_rdwr_init
(
&
li
->
li_rdwr
);
ldap_pvt_thread_mutex_init
(
&
li
->
li_modop_mutex
);
ldap_pvt_thread_rdwr_init
(
&
li
->
li_rdwr
);
SLAP_DBFLAGS
(
be
)
|=
SLAP_DBFLAG_ONE_SUFFIX
;
return
0
;
}
...
...
@@ -1401,14 +1652,15 @@ ldif_back_db_destroy( Backend *be, ConfigReply *cr )
{
struct
ldif_info
*
li
=
be
->
be_private
;
ch_free
(
li
->
li_base_path
.
bv_val
);
ldap_pvt_thread_rdwr_destroy
(
&
li
->
li_rdwr
);
ch_free
(
li
->
li_base_path
.
bv_val
);
ldap_pvt_thread_rdwr_destroy
(
&
li
->
li_rdwr
);
ldap_pvt_thread_mutex_destroy
(
&
li
->
li_modop_mutex
);
free
(
be
->
be_private
);
return
0
;
}
static
int
ldif_back_db_open
(
Backend
*
be
,
ConfigReply
*
cr
)
ldif_back_db_open
(
Backend
*
be
,
ConfigReply
*
cr
)
{
struct
ldif_info
*
li
=
(
struct
ldif_info
*
)
be
->
be_private
;
if
(
BER_BVISEMPTY
(
&
li
->
li_base_path
))
{
/* missing base path */
...
...
@@ -1419,9 +1671,7 @@ ldif_back_db_open( Backend *be, ConfigReply *cr)
}
int
ldif_back_initialize
(
BackendInfo
*
bi
)
ldif_back_initialize
(
BackendInfo
*
bi
)
{
static
char
*
controls
[]
=
{
LDAP_CONTROL_MANAGEDSAIT
,
...
...
@@ -1477,7 +1727,7 @@ ldif_back_initialize(
bi
->
bi_tool_entry_put
=
ldif_tool_entry_put
;
bi
->
bi_tool_entry_reindex
=
0
;
bi
->
bi_tool_sync
=
0
;
bi
->
bi_tool_dn2id_get
=
0
;
bi
->
bi_tool_entry_modify
=
0
;
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment