2006-01-06 04:01:23 +00:00
/*
ldb database library
2008-09-11 18:35:38 -04:00
Copyright ( C ) Simo Sorce 2005 - 2008
2006-01-06 04:01:23 +00:00
* * NOTE ! The following LGPL license applies to the ldb
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
2007-07-10 02:46:15 +00:00
version 3 of the License , or ( at your option ) any later version .
2006-01-06 04:01:23 +00:00
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
2007-07-10 03:42:26 +00:00
License along with this library ; if not , see < http : //www.gnu.org/licenses/>.
2006-01-06 04:01:23 +00:00
*/
/*
* Name : ldb
*
* Component : ldb server side sort control module
*
* Description : this module sorts the results of a search
*
* Author : Simo Sorce
*/
2010-11-01 23:36:42 +11:00
# include "replace.h"
# include "system/filesys.h"
# include "system/time.h"
2009-01-29 18:39:30 -05:00
# include "ldb_module.h"
2006-01-06 04:01:23 +00:00
struct opaque {
struct ldb_context * ldb ;
const struct ldb_attrib_handler * h ;
const char * attribute ;
int reverse ;
int result ;
} ;
2006-07-22 16:56:33 +00:00
struct sort_context {
2006-03-07 21:09:53 +00:00
struct ldb_module * module ;
2009-10-17 22:30:22 +02:00
const char * attributeName ;
const char * orderingRule ;
2006-03-07 21:09:53 +00:00
int reverse ;
struct ldb_request * req ;
struct ldb_message * * msgs ;
char * * referrals ;
2010-03-08 18:01:32 +01:00
unsigned int num_msgs ;
unsigned int num_refs ;
2006-03-07 21:09:53 +00:00
2006-12-15 13:08:57 +00:00
const struct ldb_schema_attribute * a ;
2006-03-07 21:09:53 +00:00
int sort_result ;
} ;
static int build_response ( void * mem_ctx , struct ldb_control * * * ctrls , int result , const char * desc )
{
struct ldb_control * * controls ;
2006-01-06 04:01:23 +00:00
struct ldb_sort_resp_control * resp ;
2010-03-08 18:01:32 +01:00
unsigned int i ;
2006-01-06 04:01:23 +00:00
2006-03-07 21:09:53 +00:00
if ( * ctrls ) {
controls = * ctrls ;
for ( i = 0 ; controls [ i ] ; i + + ) ;
controls = talloc_realloc ( mem_ctx , controls , struct ldb_control * , i + 2 ) ;
2006-01-06 04:01:23 +00:00
} else {
i = 0 ;
2006-03-07 21:09:53 +00:00
controls = talloc_array ( mem_ctx , struct ldb_control * , 2 ) ;
2006-01-06 04:01:23 +00:00
}
2006-03-07 21:09:53 +00:00
if ( ! controls )
2006-01-06 04:01:23 +00:00
return LDB_ERR_OPERATIONS_ERROR ;
2006-03-07 21:09:53 +00:00
* ctrls = controls ;
controls [ i + 1 ] = NULL ;
controls [ i ] = talloc ( controls , struct ldb_control ) ;
if ( ! controls [ i ] )
2006-01-06 04:01:23 +00:00
return LDB_ERR_OPERATIONS_ERROR ;
2006-03-07 21:09:53 +00:00
controls [ i ] - > oid = LDB_CONTROL_SORT_RESP_OID ;
controls [ i ] - > critical = 0 ;
2006-01-06 04:01:23 +00:00
2006-03-07 21:09:53 +00:00
resp = talloc ( controls [ i ] , struct ldb_sort_resp_control ) ;
2006-01-06 04:01:23 +00:00
if ( ! resp )
return LDB_ERR_OPERATIONS_ERROR ;
resp - > result = result ;
resp - > attr_desc = talloc_strdup ( resp , desc ) ;
if ( ! resp - > attr_desc )
return LDB_ERR_OPERATIONS_ERROR ;
2006-03-07 21:09:53 +00:00
controls [ i ] - > data = resp ;
2006-01-06 04:01:23 +00:00
return LDB_SUCCESS ;
}
static int sort_compare ( struct ldb_message * * msg1 , struct ldb_message * * msg2 , void * opaque )
2006-03-07 21:09:53 +00:00
{
2006-07-22 16:56:33 +00:00
struct sort_context * ac = talloc_get_type ( opaque , struct sort_context ) ;
2006-03-07 21:09:53 +00:00
struct ldb_message_element * el1 , * el2 ;
2009-01-29 18:39:30 -05:00
struct ldb_context * ldb ;
ldb = ldb_module_get_ctx ( ac - > module ) ;
2006-03-07 21:09:53 +00:00
2009-02-12 23:16:18 +01:00
if ( ac - > sort_result ! = 0 ) {
2006-03-07 21:09:53 +00:00
/* an error occurred previously,
* let ' s exit the sorting by returning always 0 */
return 0 ;
}
el1 = ldb_msg_find_element ( * msg1 , ac - > attributeName ) ;
el2 = ldb_msg_find_element ( * msg2 , ac - > attributeName ) ;
2009-06-10 10:33:53 +10:00
if ( ! el1 & & el2 ) {
return 1 ;
}
if ( el1 & & ! el2 ) {
return - 1 ;
}
if ( ! el1 & & ! el2 ) {
2006-03-07 21:09:53 +00:00
return 0 ;
}
if ( ac - > reverse )
2009-01-29 18:39:30 -05:00
return ac - > a - > syntax - > comparison_fn ( ldb , ac , & el2 - > values [ 0 ] , & el1 - > values [ 0 ] ) ;
2006-03-07 21:09:53 +00:00
2009-01-29 18:39:30 -05:00
return ac - > a - > syntax - > comparison_fn ( ldb , ac , & el1 - > values [ 0 ] , & el2 - > values [ 0 ] ) ;
2006-03-07 21:09:53 +00:00
}
2008-09-11 18:35:38 -04:00
static int server_sort_results ( struct sort_context * ac )
2006-03-07 21:09:53 +00:00
{
2009-01-29 18:39:30 -05:00
struct ldb_context * ldb ;
2008-09-11 18:35:38 -04:00
struct ldb_reply * ares ;
2010-03-08 18:01:32 +01:00
unsigned int i ;
int ret ;
2008-09-11 18:35:38 -04:00
2009-01-29 18:39:30 -05:00
ldb = ldb_module_get_ctx ( ac - > module ) ;
ac - > a = ldb_schema_attribute_by_name ( ldb , ac - > attributeName ) ;
2008-09-11 18:35:38 -04:00
ac - > sort_result = 0 ;
2010-02-13 13:26:51 +11:00
LDB_TYPESAFE_QSORT ( ac - > msgs , ac - > num_msgs , ac , sort_compare ) ;
2008-09-11 18:35:38 -04:00
if ( ac - > sort_result ! = LDB_SUCCESS ) {
return ac - > sort_result ;
}
for ( i = 0 ; i < ac - > num_msgs ; i + + ) {
ares = talloc_zero ( ac , struct ldb_reply ) ;
if ( ! ares ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
ares - > type = LDB_REPLY_ENTRY ;
ares - > message = talloc_move ( ares , & ac - > msgs [ i ] ) ;
2008-12-16 08:59:05 +01:00
ret = ldb_module_send_entry ( ac - > req , ares - > message , ares - > controls ) ;
2008-09-11 18:35:38 -04:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
for ( i = 0 ; i < ac - > num_refs ; i + + ) {
ares = talloc_zero ( ac , struct ldb_reply ) ;
if ( ! ares ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
ares - > type = LDB_REPLY_REFERRAL ;
ares - > referral = talloc_move ( ares , & ac - > referrals [ i ] ) ;
ret = ldb_module_send_referral ( ac - > req , ares - > referral ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
}
return LDB_SUCCESS ;
}
static int server_sort_search_callback ( struct ldb_request * req , struct ldb_reply * ares )
{
struct sort_context * ac ;
2009-01-29 18:39:30 -05:00
struct ldb_context * ldb ;
2008-09-11 18:35:38 -04:00
int ret ;
2006-03-07 21:09:53 +00:00
2008-09-11 18:35:38 -04:00
ac = talloc_get_type ( req - > context , struct sort_context ) ;
2009-01-29 18:39:30 -05:00
ldb = ldb_module_get_ctx ( ac - > module ) ;
2006-03-07 21:09:53 +00:00
2008-09-11 18:35:38 -04:00
if ( ! ares ) {
return ldb_module_done ( ac - > req , NULL , NULL ,
LDB_ERR_OPERATIONS_ERROR ) ;
}
if ( ares - > error ! = LDB_SUCCESS ) {
return ldb_module_done ( ac - > req , ares - > controls ,
ares - > response , ares - > error ) ;
}
switch ( ares - > type ) {
case LDB_REPLY_ENTRY :
2006-03-07 21:09:53 +00:00
ac - > msgs = talloc_realloc ( ac , ac - > msgs , struct ldb_message * , ac - > num_msgs + 2 ) ;
if ( ! ac - > msgs ) {
2008-09-11 18:35:38 -04:00
talloc_free ( ares ) ;
2009-01-29 18:39:30 -05:00
ldb_oom ( ldb ) ;
2008-09-11 18:35:38 -04:00
return ldb_module_done ( ac - > req , NULL , NULL ,
LDB_ERR_OPERATIONS_ERROR ) ;
2006-03-07 21:09:53 +00:00
}
2008-09-11 18:35:38 -04:00
ac - > msgs [ ac - > num_msgs ] = talloc_steal ( ac - > msgs , ares - > message ) ;
2006-03-07 21:09:53 +00:00
ac - > num_msgs + + ;
2008-09-11 18:35:38 -04:00
ac - > msgs [ ac - > num_msgs ] = NULL ;
2006-03-07 21:09:53 +00:00
2008-09-11 18:35:38 -04:00
break ;
case LDB_REPLY_REFERRAL :
2006-03-07 21:09:53 +00:00
ac - > referrals = talloc_realloc ( ac , ac - > referrals , char * , ac - > num_refs + 2 ) ;
if ( ! ac - > referrals ) {
2008-09-11 18:35:38 -04:00
talloc_free ( ares ) ;
2009-01-29 18:39:30 -05:00
ldb_oom ( ldb ) ;
2008-09-11 18:35:38 -04:00
return ldb_module_done ( ac - > req , NULL , NULL ,
LDB_ERR_OPERATIONS_ERROR ) ;
2006-03-07 21:09:53 +00:00
}
2008-09-11 18:35:38 -04:00
ac - > referrals [ ac - > num_refs ] = talloc_steal ( ac - > referrals , ares - > referral ) ;
2006-03-07 21:09:53 +00:00
ac - > num_refs + + ;
2008-09-11 18:35:38 -04:00
ac - > referrals [ ac - > num_refs ] = NULL ;
2006-03-07 21:09:53 +00:00
2008-09-11 18:35:38 -04:00
break ;
case LDB_REPLY_DONE :
ret = server_sort_results ( ac ) ;
return ldb_module_done ( ac - > req , ares - > controls ,
ares - > response , ret ) ;
2006-03-07 21:09:53 +00:00
}
talloc_free ( ares ) ;
return LDB_SUCCESS ;
}
2006-05-29 23:46:43 +00:00
static int server_sort_search ( struct ldb_module * module , struct ldb_request * req )
2006-03-07 21:09:53 +00:00
{
2006-05-29 01:30:02 +00:00
struct ldb_control * control ;
2006-03-07 21:09:53 +00:00
struct ldb_server_sort_control * * sort_ctrls ;
struct ldb_control * * saved_controls ;
2008-09-11 18:35:38 -04:00
struct ldb_control * * controls ;
struct ldb_request * down_req ;
2006-07-22 16:56:33 +00:00
struct sort_context * ac ;
2009-01-29 18:39:30 -05:00
struct ldb_context * ldb ;
2006-03-07 21:09:53 +00:00
int ret ;
2009-01-29 18:39:30 -05:00
ldb = ldb_module_get_ctx ( module ) ;
2009-05-26 15:22:13 -05:00
/* check if there's a server sort control */
2007-02-22 01:54:40 +00:00
control = ldb_request_get_control ( req , LDB_CONTROL_SERVER_SORT_OID ) ;
2006-05-29 01:30:02 +00:00
if ( control = = NULL ) {
/* not found go on */
return ldb_next_request ( module , req ) ;
}
2008-09-11 18:35:38 -04:00
ac = talloc_zero ( req , struct sort_context ) ;
if ( ac = = NULL ) {
2009-01-29 18:39:30 -05:00
ldb_oom ( ldb ) ;
2006-03-07 21:09:53 +00:00
return LDB_ERR_OPERATIONS_ERROR ;
}
2008-09-11 18:35:38 -04:00
ac - > module = module ;
ac - > req = req ;
2006-03-07 21:09:53 +00:00
sort_ctrls = talloc_get_type ( control - > data , struct ldb_server_sort_control * ) ;
if ( ! sort_ctrls ) {
return LDB_ERR_PROTOCOL_ERROR ;
}
/* FIXME: we do not support more than one attribute for sorting right now */
/* FIXME: we need to check if the attribute type exist or return an error */
if ( sort_ctrls [ 1 ] ! = NULL ) {
if ( control - > critical ) {
2008-09-11 18:35:38 -04:00
/* callback immediately */
ret = build_response ( req , & controls ,
LDB_ERR_UNWILLING_TO_PERFORM ,
" sort control is not complete yet " ) ;
if ( ret ! = LDB_SUCCESS ) {
return ldb_module_done ( req , NULL , NULL ,
LDB_ERR_OPERATIONS_ERROR ) ;
2006-03-07 21:09:53 +00:00
}
2008-09-11 18:35:38 -04:00
return ldb_module_done ( req , controls , NULL , ret ) ;
2006-03-07 21:09:53 +00:00
} else {
/* just pass the call down and don't do any sorting */
2008-09-11 18:35:38 -04:00
return ldb_next_request ( module , req ) ;
2006-03-07 21:09:53 +00:00
}
}
ac - > attributeName = sort_ctrls [ 0 ] - > attributeName ;
ac - > orderingRule = sort_ctrls [ 0 ] - > orderingRule ;
ac - > reverse = sort_ctrls [ 0 ] - > reverse ;
2009-01-29 18:39:30 -05:00
ret = ldb_build_search_req_ex ( & down_req , ldb , ac ,
2008-09-11 18:35:38 -04:00
req - > op . search . base ,
req - > op . search . scope ,
req - > op . search . tree ,
req - > op . search . attrs ,
req - > controls ,
ac ,
server_sort_search_callback ,
req ) ;
if ( ret ! = LDB_SUCCESS ) {
2009-10-06 19:27:17 +02:00
return ret ;
2008-09-11 18:35:38 -04:00
}
2006-03-07 21:09:53 +00:00
/* save it locally and remove it from the list */
/* we do not need to replace them later as we
* are keeping the original req intact */
2010-12-17 23:00:46 +01:00
if ( ! ldb_save_controls ( control , down_req , & saved_controls ) ) {
2006-03-07 21:09:53 +00:00
return LDB_ERR_OPERATIONS_ERROR ;
}
2008-09-11 18:35:38 -04:00
return ldb_next_request ( module , down_req ) ;
2007-12-24 01:38:37 -06:00
}
2006-03-02 16:32:53 +00:00
static int server_sort_init ( struct ldb_module * module )
2006-01-06 16:12:45 +00:00
{
2009-01-29 18:39:30 -05:00
struct ldb_context * ldb ;
2006-01-06 16:12:45 +00:00
int ret ;
2009-01-29 18:39:30 -05:00
ldb = ldb_module_get_ctx ( module ) ;
2008-09-11 18:35:38 -04:00
ret = ldb_mod_register_control ( module , LDB_CONTROL_SERVER_SORT_OID ) ;
2006-01-06 16:12:45 +00:00
if ( ret ! = LDB_SUCCESS ) {
2009-01-29 18:39:30 -05:00
ldb_debug ( ldb , LDB_DEBUG_WARNING ,
2008-09-11 18:35:38 -04:00
" server_sort: "
2009-07-10 22:44:27 +02:00
" Unable to register control with rootdse! " ) ;
2006-01-06 16:12:45 +00:00
}
2006-03-02 16:32:53 +00:00
return ldb_next_init ( module ) ;
2006-01-06 16:12:45 +00:00
}
2010-11-01 14:59:28 +11:00
static const struct ldb_module_ops ldb_server_sort_module_ops = {
2006-01-06 04:01:23 +00:00
. name = " server_sort " ,
2006-05-29 23:46:43 +00:00
. search = server_sort_search ,
2006-03-02 16:32:53 +00:00
. init_context = server_sort_init
2006-01-06 04:01:23 +00:00
} ;
2010-11-01 14:59:28 +11:00
int ldb_server_sort_init ( const char * version )
{
2010-11-01 22:30:23 +11:00
LDB_MODULE_CHECK_VERSION ( version ) ;
2010-11-01 14:59:28 +11:00
return ldb_register_module ( & ldb_server_sort_module_ops ) ;
}