Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
openldap
OpenLDAP
Commits
ad9f3ebe
Commit
ad9f3ebe
authored
Nov 29, 2004
by
Howard Chu
Browse files
Backglue hastily modified as an overlay
parent
decfd721
Changes
2
Hide whitespace changes
Inline
Side-by-side
servers/slapd/overlays/glue.c
0 → 100644
View file @
ad9f3ebe
/* glue.c - backend glue overlay */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2001-2004 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/*
* Functions to glue a bunch of other backends into a single tree.
* All of the glued backends must share a common suffix. E.g., you
* can glue o=foo and ou=bar,o=foo but you can't glue o=foo and o=bar.
*
* The purpose of these functions is to allow you to split a single database
* into pieces (for load balancing purposes, whatever) but still be able
* to treat it as a single database after it's been split. As such, each
* of the glued backends should have identical rootdn.
* -- Howard Chu
*/
#include
"portable.h"
#ifdef SLAPD_OVER_GLUE
#include
<stdio.h>
#include
<ac/string.h>
#include
<ac/socket.h>
#define SLAPD_TOOLS
#include
"slap.h"
typedef
struct
gluenode
{
BackendDB
*
gn_be
;
int
gn_bx
;
struct
berval
gn_pdn
;
int
gn_async
;
}
gluenode
;
typedef
struct
glueinfo
{
int
gi_nodes
;
struct
berval
gi_pdn
;
gluenode
gi_n
[
1
];
}
glueinfo
;
static
slap_overinst
glue
;
static
int
glueMode
;
static
BackendDB
*
glueBack
;
static
slap_response
glue_op_response
;
/* Just like select_backend, but only for our backends */
static
BackendDB
*
glue_back_select
(
BackendDB
*
be
,
struct
berval
*
dn
)
{
slap_overinst
*
on
=
(
slap_overinst
*
)
be
->
bd_info
;
glueinfo
*
gi
=
(
glueinfo
*
)
on
->
on_bi
.
bi_private
;
int
i
;
for
(
i
=
0
;
i
<
gi
->
gi_nodes
;
i
++
)
{
assert
(
gi
->
gi_n
[
i
].
gn_be
->
be_nsuffix
);
if
(
dnIsSuffix
(
dn
,
&
gi
->
gi_n
[
i
].
gn_be
->
be_nsuffix
[
0
]))
{
return
gi
->
gi_n
[
i
].
gn_be
;
}
}
be
->
bd_info
=
on
->
on_info
->
oi_orig
;
return
be
;
}
typedef
struct
glue_state
{
int
err
;
int
slimit
;
int
matchlen
;
char
*
matched
;
int
nrefs
;
BerVarray
refs
;
}
glue_state
;
static
int
glue_op_response
(
Operation
*
op
,
SlapReply
*
rs
)
{
glue_state
*
gs
=
op
->
o_callback
->
sc_private
;
switch
(
rs
->
sr_type
)
{
case
REP_SEARCH
:
if
(
gs
->
slimit
!=
SLAP_NO_LIMIT
&&
rs
->
sr_nentries
>=
gs
->
slimit
)
{
rs
->
sr_err
=
gs
->
err
=
LDAP_SIZELIMIT_EXCEEDED
;
return
-
1
;
}
/* fallthru */
case
REP_SEARCHREF
:
return
SLAP_CB_CONTINUE
;
default:
if
(
rs
->
sr_err
==
LDAP_SUCCESS
||
rs
->
sr_err
==
LDAP_SIZELIMIT_EXCEEDED
||
rs
->
sr_err
==
LDAP_TIMELIMIT_EXCEEDED
||
rs
->
sr_err
==
LDAP_ADMINLIMIT_EXCEEDED
||
rs
->
sr_err
==
LDAP_NO_SUCH_OBJECT
||
gs
->
err
!=
LDAP_SUCCESS
)
gs
->
err
=
rs
->
sr_err
;
if
(
gs
->
err
==
LDAP_SUCCESS
&&
gs
->
matched
)
{
ch_free
(
gs
->
matched
);
gs
->
matched
=
NULL
;
gs
->
matchlen
=
0
;
}
if
(
gs
->
err
!=
LDAP_SUCCESS
&&
rs
->
sr_matched
)
{
int
len
;
len
=
strlen
(
rs
->
sr_matched
);
if
(
len
>
gs
->
matchlen
)
{
if
(
gs
->
matched
)
ch_free
(
gs
->
matched
);
gs
->
matched
=
ch_strdup
(
rs
->
sr_matched
);
gs
->
matchlen
=
len
;
}
}
if
(
rs
->
sr_ref
)
{
int
i
,
j
,
k
;
BerVarray
new
;
for
(
i
=
0
;
rs
->
sr_ref
[
i
].
bv_val
;
i
++
);
j
=
gs
->
nrefs
;
if
(
!
j
)
{
new
=
ch_malloc
((
i
+
1
)
*
sizeof
(
struct
berval
));
}
else
{
new
=
ch_realloc
(
gs
->
refs
,
(
j
+
i
+
1
)
*
sizeof
(
struct
berval
));
}
for
(
k
=
0
;
k
<
i
;
j
++
,
k
++
)
{
ber_dupbv
(
&
new
[
j
],
&
rs
->
sr_ref
[
k
]
);
}
new
[
j
].
bv_val
=
NULL
;
gs
->
nrefs
=
j
;
gs
->
refs
=
new
;
}
}
return
0
;
}
static
int
glue_op_search
(
Operation
*
op
,
SlapReply
*
rs
)
{
slap_overinst
*
on
=
(
slap_overinst
*
)
op
->
o_bd
->
bd_info
;
glueinfo
*
gi
=
(
glueinfo
*
)
on
->
on_bi
.
bi_private
;
BackendDB
*
b0
=
op
->
o_bd
;
BackendDB
*
b1
=
NULL
,
*
btmp
;
BackendInfo
*
bi0
=
op
->
o_bd
->
bd_info
;
int
i
;
long
stoptime
=
0
;
glue_state
gs
=
{
0
,
0
,
0
,
NULL
,
0
,
NULL
};
slap_callback
cb
=
{
NULL
,
glue_op_response
,
NULL
,
NULL
};
int
scope0
,
slimit0
,
tlimit0
;
struct
berval
dn
,
ndn
,
*
pdn
;
cb
.
sc_private
=
&
gs
;
cb
.
sc_next
=
op
->
o_callback
;
stoptime
=
slap_get_time
()
+
op
->
ors_tlimit
;
op
->
o_bd
=
glue_back_select
(
b0
,
&
op
->
o_req_ndn
);
b0
->
bd_info
=
on
->
on_info
->
oi_orig
;
switch
(
op
->
ors_scope
)
{
case
LDAP_SCOPE_BASE
:
return
SLAP_CB_CONTINUE
;
case
LDAP_SCOPE_ONELEVEL
:
case
LDAP_SCOPE_SUBTREE
:
#ifdef LDAP_SCOPE_SUBORDINATE
case
LDAP_SCOPE_SUBORDINATE
:
/* FIXME */
#endif
if
(
op
->
o_sync
)
{
if
(
op
->
o_bd
&&
op
->
o_bd
->
be_search
)
{
rs
->
sr_err
=
op
->
o_bd
->
be_search
(
op
,
rs
);
}
else
{
send_ldap_error
(
op
,
rs
,
LDAP_UNWILLING_TO_PERFORM
,
"No search target found"
);
}
return
rs
->
sr_err
;
}
op
->
o_callback
=
&
cb
;
rs
->
sr_err
=
gs
.
err
=
LDAP_UNWILLING_TO_PERFORM
;
scope0
=
op
->
ors_scope
;
slimit0
=
gs
.
slimit
=
op
->
ors_slimit
;
tlimit0
=
op
->
ors_tlimit
;
dn
=
op
->
o_req_dn
;
ndn
=
op
->
o_req_ndn
;
b1
=
op
->
o_bd
;
/*
* Execute in reverse order, most general first
*/
for
(
i
=
gi
->
gi_nodes
;
i
>=
0
;
i
--
)
{
if
(
i
==
gi
->
gi_nodes
)
{
btmp
=
b0
;
pdn
=
&
gi
->
gi_pdn
;
}
else
{
btmp
=
gi
->
gi_n
[
i
].
gn_be
;
pdn
=
&
gi
->
gi_n
[
i
].
gn_pdn
;
}
if
(
!
btmp
||
!
btmp
->
be_search
)
continue
;
if
(
!
dnIsSuffix
(
&
btmp
->
be_nsuffix
[
0
],
&
b1
->
be_nsuffix
[
0
]))
continue
;
if
(
tlimit0
!=
SLAP_NO_LIMIT
)
{
op
->
ors_tlimit
=
stoptime
-
slap_get_time
();
if
(
op
->
ors_tlimit
<=
0
)
{
rs
->
sr_err
=
gs
.
err
=
LDAP_TIMELIMIT_EXCEEDED
;
break
;
}
}
if
(
slimit0
!=
SLAP_NO_LIMIT
)
{
op
->
ors_slimit
=
slimit0
-
rs
->
sr_nentries
;
if
(
op
->
ors_slimit
<
0
)
{
rs
->
sr_err
=
gs
.
err
=
LDAP_SIZELIMIT_EXCEEDED
;
break
;
}
}
rs
->
sr_err
=
0
;
/*
* check for abandon
*/
if
(
op
->
o_abandon
)
{
goto
end_of_loop
;
}
op
->
o_bd
=
btmp
;
assert
(
op
->
o_bd
->
be_suffix
);
assert
(
op
->
o_bd
->
be_nsuffix
);
if
(
scope0
==
LDAP_SCOPE_ONELEVEL
&&
dn_match
(
pdn
,
&
ndn
))
{
op
->
ors_scope
=
LDAP_SCOPE_BASE
;
op
->
o_req_dn
=
op
->
o_bd
->
be_suffix
[
0
];
op
->
o_req_ndn
=
op
->
o_bd
->
be_nsuffix
[
0
];
rs
->
sr_err
=
op
->
o_bd
->
be_search
(
op
,
rs
);
}
else
if
(
scope0
==
LDAP_SCOPE_SUBTREE
&&
dn_match
(
&
op
->
o_bd
->
be_nsuffix
[
0
],
&
ndn
))
{
rs
->
sr_err
=
op
->
o_bd
->
be_search
(
op
,
rs
);
}
else
if
(
scope0
==
LDAP_SCOPE_SUBTREE
&&
dnIsSuffix
(
&
op
->
o_bd
->
be_nsuffix
[
0
],
&
ndn
))
{
op
->
o_req_dn
=
op
->
o_bd
->
be_suffix
[
0
];
op
->
o_req_ndn
=
op
->
o_bd
->
be_nsuffix
[
0
];
rs
->
sr_err
=
op
->
o_bd
->
be_search
(
op
,
rs
);
if
(
rs
->
sr_err
==
LDAP_NO_SUCH_OBJECT
)
{
gs
.
err
=
LDAP_SUCCESS
;
}
}
else
if
(
dnIsSuffix
(
&
ndn
,
&
op
->
o_bd
->
be_nsuffix
[
0
]))
{
rs
->
sr_err
=
op
->
o_bd
->
be_search
(
op
,
rs
);
}
switch
(
gs
.
err
)
{
/*
* Add errors that should result in dropping
* the search
*/
case
LDAP_SIZELIMIT_EXCEEDED
:
case
LDAP_TIMELIMIT_EXCEEDED
:
case
LDAP_ADMINLIMIT_EXCEEDED
:
case
LDAP_NO_SUCH_OBJECT
:
goto
end_of_loop
;
default:
break
;
}
}
end_of_loop:
;
op
->
ors_scope
=
scope0
;
op
->
ors_slimit
=
slimit0
;
op
->
ors_tlimit
=
tlimit0
;
op
->
o_req_dn
=
dn
;
op
->
o_req_ndn
=
ndn
;
break
;
}
if
(
!
op
->
o_abandon
)
{
op
->
o_callback
=
cb
.
sc_next
;
rs
->
sr_err
=
gs
.
err
;
rs
->
sr_matched
=
gs
.
matched
;
rs
->
sr_ref
=
gs
.
refs
;
send_ldap_result
(
op
,
rs
);
}
op
->
o_bd
=
b0
;
op
->
o_bd
->
bd_info
=
bi0
;
if
(
gs
.
matched
)
free
(
gs
.
matched
);
if
(
gs
.
refs
)
ber_bvarray_free
(
gs
.
refs
);
return
rs
->
sr_err
;
}
static
BackendDB
toolDB
;
static
int
glue_tool_entry_open
(
BackendDB
*
b0
,
int
mode
)
{
slap_overinfo
*
oi
=
(
slap_overinfo
*
)
b0
->
bd_info
;
/* We don't know which backend to talk to yet, so just
* remember the mode and move on...
*/
glueMode
=
mode
;
glueBack
=
NULL
;
toolDB
=
*
b0
;
toolDB
.
bd_info
=
oi
->
oi_orig
;
return
0
;
}
static
int
glue_tool_entry_close
(
BackendDB
*
b0
)
{
int
rc
=
0
;
if
(
glueBack
)
{
if
(
!
glueBack
->
be_entry_close
)
return
0
;
rc
=
glueBack
->
be_entry_close
(
glueBack
);
}
return
rc
;
}
static
slap_overinst
*
glue_tool_inst
(
BackendInfo
*
bi
)
{
slap_overinfo
*
oi
=
(
slap_overinfo
*
)
bi
;
slap_overinst
*
on
;
for
(
on
=
oi
->
oi_list
;
on
;
on
=
on
->
on_next
)
{
if
(
!
strcmp
(
on
->
on_bi
.
bi_type
,
glue
.
on_bi
.
bi_type
))
return
on
;
}
return
NULL
;
}
/* This function will only be called in tool mode */
static
int
glue_open
(
BackendInfo
*
bi
)
{
slap_overinst
*
on
=
glue_tool_inst
(
bi
);
glueinfo
*
gi
=
on
->
on_bi
.
bi_private
;
int
i
,
rc
=
0
;
/* If we were invoked in tool mode, open all the underlying backends */
if
(
slapMode
&
SLAP_TOOL_MODE
)
{
for
(
i
=
0
;
i
<
gi
->
gi_nodes
;
i
++
)
{
gi
->
gi_n
[
i
].
gn_be
=
backendDB
+
gi
->
gi_n
[
i
].
gn_bx
;
rc
=
backend_startup
(
gi
->
gi_n
[
i
].
gn_be
);
if
(
rc
)
break
;
}
}
/* other case is impossible */
return
rc
;
}
/* This function will only be called in tool mode */
static
int
glue_close
(
BackendInfo
*
bi
)
{
slap_overinst
*
on
=
glue_tool_inst
(
bi
);
glueinfo
*
gi
=
on
->
on_bi
.
bi_private
;
int
i
,
rc
=
0
;
if
(
slapMode
&
SLAP_TOOL_MODE
)
{
for
(
i
=
0
;
i
<
gi
->
gi_nodes
;
i
++
)
{
rc
=
backend_shutdown
(
gi
->
gi_n
[
i
].
gn_be
);
if
(
rc
)
break
;
}
}
return
rc
;
}
static
ID
glue_tool_entry_first
(
BackendDB
*
b0
)
{
slap_overinst
*
on
=
glue_tool_inst
(
b0
->
bd_info
);
glueinfo
*
gi
=
on
->
on_bi
.
bi_private
;
int
i
;
/* If we're starting from scratch, start at the most general */
if
(
!
glueBack
)
{
if
(
toolDB
.
be_entry_open
&&
toolDB
.
be_entry_first
)
{
glueBack
=
&
toolDB
;
}
else
{
for
(
i
=
gi
->
gi_nodes
-
1
;
i
>=
0
;
i
--
)
{
if
(
gi
->
gi_n
[
i
].
gn_be
->
be_entry_open
&&
gi
->
gi_n
[
i
].
gn_be
->
be_entry_first
)
{
glueBack
=
gi
->
gi_n
[
i
].
gn_be
;
break
;
}
}
}
}
if
(
!
glueBack
||
!
glueBack
->
be_entry_open
||
!
glueBack
->
be_entry_first
||
glueBack
->
be_entry_open
(
glueBack
,
glueMode
)
!=
0
)
return
NOID
;
return
glueBack
->
be_entry_first
(
glueBack
);
}
static
ID
glue_tool_entry_next
(
BackendDB
*
b0
)
{
slap_overinst
*
on
=
glue_tool_inst
(
b0
->
bd_info
);
glueinfo
*
gi
=
on
->
on_bi
.
bi_private
;
int
i
;
ID
rc
;
if
(
!
glueBack
||
!
glueBack
->
be_entry_next
)
return
NOID
;
rc
=
glueBack
->
be_entry_next
(
glueBack
);
/* If we ran out of entries in one database, move on to the next */
while
(
rc
==
NOID
)
{
if
(
glueBack
&&
glueBack
->
be_entry_close
)
glueBack
->
be_entry_close
(
glueBack
);
for
(
i
=
0
;
i
<
gi
->
gi_nodes
;
i
++
)
{
if
(
gi
->
gi_n
[
i
].
gn_be
==
glueBack
)
break
;
}
if
(
i
==
0
)
{
glueBack
=
NULL
;
break
;
}
else
{
glueBack
=
gi
->
gi_n
[
i
-
1
].
gn_be
;
rc
=
glue_tool_entry_first
(
b0
);
}
}
return
rc
;
}
static
Entry
*
glue_tool_entry_get
(
BackendDB
*
b0
,
ID
id
)
{
if
(
!
glueBack
||
!
glueBack
->
be_entry_get
)
return
NULL
;
return
glueBack
->
be_entry_get
(
glueBack
,
id
);
}
static
ID
glue_tool_entry_put
(
BackendDB
*
b0
,
Entry
*
e
,
struct
berval
*
text
)
{
BackendDB
*
be
,
b2
;
int
rc
;
b2
=
*
b0
;
b2
.
bd_info
=
(
BackendInfo
*
)
glue_tool_inst
(
b0
->
bd_info
);
be
=
glue_back_select
(
&
b2
,
&
e
->
e_nname
);
if
(
be
==
&
b2
)
be
=
&
toolDB
;
if
(
!
be
->
be_entry_put
)
return
NOID
;
if
(
!
glueBack
)
{
rc
=
be
->
be_entry_open
(
be
,
glueMode
);
if
(
rc
!=
0
)
return
NOID
;
}
else
if
(
be
!=
glueBack
)
{
/* If this entry belongs in a different branch than the
* previous one, close the current database and open the
* new one.
*/
glueBack
->
be_entry_close
(
glueBack
);
rc
=
be
->
be_entry_open
(
be
,
glueMode
);
if
(
rc
!=
0
)
return
NOID
;
}
glueBack
=
be
;
return
be
->
be_entry_put
(
be
,
e
,
text
);
}
static
int
glue_tool_entry_reindex
(
BackendDB
*
b0
,
ID
id
)
{
if
(
!
glueBack
||
!
glueBack
->
be_entry_reindex
)
return
-
1
;
return
glueBack
->
be_entry_reindex
(
glueBack
,
id
);
}
static
int
glue_tool_sync
(
BackendDB
*
b0
)
{
slap_overinst
*
on
=
glue_tool_inst
(
b0
->
bd_info
);
glueinfo
*
gi
=
on
->
on_bi
.
bi_private
;
int
i
;
/* just sync everyone */
for
(
i
=
0
;
i
<
gi
->
gi_nodes
;
i
++
)
if
(
gi
->
gi_n
[
i
].
gn_be
->
be_sync
)
gi
->
gi_n
[
i
].
gn_be
->
be_sync
(
gi
->
gi_n
[
i
].
gn_be
);
return
0
;
}
static
int
glue_db_init
(
BackendDB
*
be
)
{
slap_overinst
*
on
=
(
slap_overinst
*
)
be
->
bd_info
;
slap_overinfo
*
oi
=
on
->
on_info
;
glueinfo
*
gi
;
gi
=
ch_calloc
(
1
,
sizeof
(
glueinfo
));
on
->
on_bi
.
bi_private
=
gi
;
dnParent
(
be
->
be_nsuffix
,
&
gi
->
gi_pdn
);
/* Currently the overlay framework doesn't handle these entry points
* but we need them....
*/
oi
->
oi_bi
.
bi_open
=
glue_open
;
oi
->
oi_bi
.
bi_close
=
glue_close
;
oi
->
oi_bi
.
bi_tool_entry_open
=
glue_tool_entry_open
;
oi
->
oi_bi
.
bi_tool_entry_close
=
glue_tool_entry_close
;
oi
->
oi_bi
.
bi_tool_entry_first
=
glue_tool_entry_first
;
oi
->
oi_bi
.
bi_tool_entry_next
=
glue_tool_entry_next
;
oi
->
oi_bi
.
bi_tool_entry_get
=
glue_tool_entry_get
;
oi
->
oi_bi
.
bi_tool_entry_put
=
glue_tool_entry_put
;
oi
->
oi_bi
.
bi_tool_entry_reindex
=
glue_tool_entry_reindex
;
oi
->
oi_bi
.
bi_tool_sync
=
glue_tool_sync
;
/*FIXME : need to add support */
oi
->
oi_bi
.
bi_tool_dn2id_get
=
0
;
oi
->
oi_bi
.
bi_tool_id2entry_get
=
0
;
oi
->
oi_bi
.
bi_tool_entry_modify
=
0
;
return
0
;
}
static
int
glue_db_destroy
(
BackendDB
*
be
)
{
slap_overinst
*
on
=
(
slap_overinst
*
)
be
->
bd_info
;
glueinfo
*
gi
=
(
glueinfo
*
)
on
->
on_bi
.
bi_private
;
free
(
gi
);
return
SLAP_CB_CONTINUE
;
}
static
int
glue_db_open
(
BackendDB
*
be
)
{
slap_overinst
*
on
=
(
slap_overinst
*
)
be
->
bd_info
;
glueinfo
*
gi
=
(
glueinfo
*
)
on
->
on_bi
.
bi_private
;
int
i
;
for
(
i
=
0
;
i
<
gi
->
gi_nodes
;
i
++
)
{
gi
->
gi_n
[
i
].
gn_be
=
backendDB
+
gi
->
gi_n
[
i
].
gn_bx
;
}
return
0
;
}
static
int