2004-09-13 14:36:59 +04:00
/*
Unix SMB / CIFS implementation .
2005-06-19 11:21:18 +04:00
2004-09-13 14:36:59 +04:00
LDAP server
2005-06-19 11:21:18 +04:00
Copyright ( C ) Andrew Tridgell 2005
2004-09-13 14:36:59 +04:00
Copyright ( C ) Volker Lendecke 2004
Copyright ( C ) Stefan Metzmacher 2004
2009-05-29 11:42:31 +04:00
2004-09-13 14:36:59 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2004-09-13 14:36:59 +04:00
( at your option ) any later version .
2009-05-29 11:42:31 +04:00
2004-09-13 14:36:59 +04:00
This program 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 General Public License for more details .
2009-05-29 11:42:31 +04:00
2004-09-13 14:36:59 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2004-09-13 14:36:59 +04:00
*/
# include "includes.h"
2010-09-22 16:24:03 +04:00
# include "system/network.h"
2005-02-03 14:56:03 +03:00
# include "lib/events/events.h"
2004-11-02 05:57:18 +03:00
# include "auth/auth.h"
2006-11-07 03:48:36 +03:00
# include "auth/credentials/credentials.h"
# include "librpc/gen_ndr/ndr_samr.h"
2008-10-11 23:31:42 +04:00
# include "../lib/util/dlinklist.h"
# include "../lib/util/asn1.h"
2004-11-02 09:52:59 +03:00
# include "ldap_server/ldap_server.h"
2005-06-19 11:21:18 +04:00
# include "smbd/service_task.h"
2005-01-30 03:54:57 +03:00
# include "smbd/service_stream.h"
2006-03-07 17:13:38 +03:00
# include "smbd/service.h"
2006-08-21 05:25:20 +04:00
# include "smbd/process_model.h"
2005-06-19 11:21:18 +04:00
# include "lib/tls/tls.h"
2005-07-10 05:08:10 +04:00
# include "lib/messaging/irpc.h"
2011-02-10 06:12:51 +03:00
# include <ldb.h>
# include <ldb_errors.h>
2008-04-02 06:53:27 +04:00
# include "libcli/ldap/ldap_proto.h"
2006-03-07 14:07:23 +03:00
# include "system/network.h"
2006-08-17 17:37:04 +04:00
# include "lib/socket/netif.h"
2006-12-13 14:19:51 +03:00
# include "dsdb/samdb/samdb.h"
2007-09-08 16:42:09 +04:00
# include "param/param.h"
2010-09-22 16:24:03 +04:00
# include "../lib/tsocket/tsocket.h"
# include "../lib/util/tevent_ntstatus.h"
# include "../libcli/util/tstream.h"
2015-12-28 22:01:54 +03:00
# include "libds/common/roles.h"
2010-10-05 09:47:51 +04:00
2010-09-22 16:24:03 +04:00
static void ldapsrv_terminate_connection_done ( struct tevent_req * subreq ) ;
2004-10-08 16:19:08 +04:00
2010-10-05 09:47:51 +04:00
/*
2010-09-22 16:24:03 +04:00
close the socket and shutdown a server_context
2010-10-05 09:47:51 +04:00
*/
2010-09-22 16:24:03 +04:00
static void ldapsrv_terminate_connection ( struct ldapsrv_connection * conn ,
const char * reason )
2010-10-05 09:47:51 +04:00
{
2010-09-22 16:24:03 +04:00
struct tevent_req * subreq ;
2010-10-05 09:47:51 +04:00
2010-09-22 16:24:03 +04:00
if ( conn - > limits . reason ) {
2010-09-22 16:24:03 +04:00
return ;
2010-09-07 05:57:44 +04:00
}
2015-07-23 13:08:42 +03:00
DLIST_REMOVE ( conn - > service - > connections , conn ) ;
2010-09-22 16:24:03 +04:00
conn - > limits . endtime = timeval_current_ofs ( 0 , 500 ) ;
2010-10-05 09:47:51 +04:00
2010-09-22 16:24:03 +04:00
tevent_queue_stop ( conn - > sockets . send_queue ) ;
2015-07-23 13:06:11 +03:00
TALLOC_FREE ( conn - > sockets . read_req ) ;
2010-09-22 16:24:03 +04:00
if ( conn - > active_call ) {
tevent_req_cancel ( conn - > active_call ) ;
conn - > active_call = NULL ;
2010-10-05 09:47:51 +04:00
}
2010-09-22 16:24:03 +04:00
conn - > limits . reason = talloc_strdup ( conn , reason ) ;
if ( conn - > limits . reason = = NULL ) {
TALLOC_FREE ( conn - > sockets . tls ) ;
TALLOC_FREE ( conn - > sockets . sasl ) ;
TALLOC_FREE ( conn - > sockets . raw ) ;
stream_terminate_connection ( conn - > connection , reason ) ;
return ;
2010-09-07 05:57:44 +04:00
}
2010-09-22 16:24:03 +04:00
subreq = tstream_disconnect_send ( conn ,
conn - > connection - > event . ctx ,
conn - > sockets . active ) ;
if ( subreq = = NULL ) {
TALLOC_FREE ( conn - > sockets . tls ) ;
TALLOC_FREE ( conn - > sockets . sasl ) ;
TALLOC_FREE ( conn - > sockets . raw ) ;
stream_terminate_connection ( conn - > connection , reason ) ;
return ;
2010-10-05 09:47:51 +04:00
}
2010-09-22 16:24:03 +04:00
tevent_req_set_endtime ( subreq ,
conn - > connection - > event . ctx ,
conn - > limits . endtime ) ;
tevent_req_set_callback ( subreq , ldapsrv_terminate_connection_done , conn ) ;
2010-10-05 09:47:51 +04:00
}
2004-10-10 02:00:00 +04:00
2010-09-22 16:24:03 +04:00
static void ldapsrv_terminate_connection_done ( struct tevent_req * subreq )
2010-10-05 09:47:51 +04:00
{
2010-09-22 16:24:03 +04:00
struct ldapsrv_connection * conn =
tevent_req_callback_data ( subreq ,
struct ldapsrv_connection ) ;
int sys_errno ;
2018-05-22 18:10:07 +03:00
bool ok ;
2004-10-08 16:19:08 +04:00
2012-09-27 05:31:39 +04:00
tstream_disconnect_recv ( subreq , & sys_errno ) ;
2010-09-22 16:24:03 +04:00
TALLOC_FREE ( subreq ) ;
2004-10-08 16:19:08 +04:00
2010-09-22 16:24:03 +04:00
if ( conn - > sockets . active = = conn - > sockets . raw ) {
TALLOC_FREE ( conn - > sockets . tls ) ;
TALLOC_FREE ( conn - > sockets . sasl ) ;
TALLOC_FREE ( conn - > sockets . raw ) ;
stream_terminate_connection ( conn - > connection ,
conn - > limits . reason ) ;
return ;
2004-10-08 16:19:08 +04:00
}
2010-10-05 09:47:51 +04:00
2010-09-22 16:24:03 +04:00
TALLOC_FREE ( conn - > sockets . tls ) ;
TALLOC_FREE ( conn - > sockets . sasl ) ;
conn - > sockets . active = conn - > sockets . raw ;
subreq = tstream_disconnect_send ( conn ,
conn - > connection - > event . ctx ,
conn - > sockets . active ) ;
if ( subreq = = NULL ) {
TALLOC_FREE ( conn - > sockets . raw ) ;
stream_terminate_connection ( conn - > connection ,
conn - > limits . reason ) ;
return ;
2010-10-05 09:47:51 +04:00
}
2018-05-22 18:10:07 +03:00
ok = tevent_req_set_endtime ( subreq ,
conn - > connection - > event . ctx ,
conn - > limits . endtime ) ;
if ( ! ok ) {
TALLOC_FREE ( conn - > sockets . raw ) ;
stream_terminate_connection ( conn - > connection ,
conn - > limits . reason ) ;
return ;
}
2010-09-22 16:24:03 +04:00
tevent_req_set_callback ( subreq , ldapsrv_terminate_connection_done , conn ) ;
2006-01-14 01:48:08 +03:00
}
2004-09-13 14:36:59 +04:00
/*
called when a LDAP socket becomes readable
*/
r17197: This patch moves the encryption of bulk data on SASL negotiated security
contexts from the application layer into the socket layer.
This improves a number of correctness aspects, as we now allow LDAP
packets to cross multiple SASL packets. It should also make it much
easier to write async LDAP tests from windows clients, as they use SASL
by default. It is also vital to allowing OpenLDAP clients to use GSSAPI
against Samba4, as it negotiates a rather small SASL buffer size.
This patch mirrors the earlier work done to move TLS into the socket
layer.
Unusual in this pstch is the extra read callback argument I take. As
SASL is a layer on top of a socket, it is entirely possible for the
SASL layer to drain a socket dry, but for the caller not to have read
all the decrypted data. This would leave the system without an event
to restart the read (as the socket is dry).
As such, I re-invoke the read handler from a timed callback, which
should trigger on the next running of the event loop. I believe that
the TLS code does require a similar callback.
In trying to understand why this is required, imagine a SASL-encrypted
LDAP packet in the following formation:
+-----------------+---------------------+
| SASL Packet #1 | SASL Packet #2 |
----------------------------------------+
| LDAP Packet #1 | LDAP Packet #2 |
----------------------------------------+
In the old code, this was illegal, but it is perfectly standard
SASL-encrypted LDAP. Without the callback, we would read and process
the first LDAP packet, and the SASL code would have read the second SASL
packet (to decrypt enough data for the LDAP packet), and no data would
remain on the socket.
Without data on the socket, read events stop. That is why I add timed
events, until the SASL buffer is drained.
Another approach would be to add a hack to the event system, to have it
pretend there remained data to read off the network (but that is ugly).
In improving the code, to handle more real-world cases, I've been able
to remove almost all the special-cases in the testnonblock code. The
only special case is that we must use a deterministic partial packet
when calling send, rather than a random length. (1 + n/2). This is
needed because of the way the SASL and TLS code works, and the 'resend
on failure' requirements.
Andrew Bartlett
(This used to be commit 5d7c9c12cb2b39673172a357092b80cd814850b0)
2006-07-23 06:50:08 +04:00
void ldapsrv_recv ( struct stream_connection * c , uint16_t flags )
2004-09-13 14:36:59 +04:00
{
2010-09-22 16:24:03 +04:00
smb_panic ( __location__ ) ;
2004-09-13 14:36:59 +04:00
}
2005-11-10 04:41:47 +03:00
2004-09-13 14:36:59 +04:00
/*
called when a LDAP socket becomes writable
*/
2005-06-19 13:31:34 +04:00
static void ldapsrv_send ( struct stream_connection * c , uint16_t flags )
2004-09-13 14:36:59 +04:00
{
2010-09-22 16:24:03 +04:00
smb_panic ( __location__ ) ;
2006-01-13 03:38:35 +03:00
}
2006-01-13 18:40:15 +03:00
static int ldapsrv_load_limits ( struct ldapsrv_connection * conn )
{
TALLOC_CTX * tmp_ctx ;
const char * attrs [ ] = { " configurationNamingContext " , NULL } ;
const char * attrs2 [ ] = { " lDAPAdminLimits " , NULL } ;
struct ldb_message_element * el ;
struct ldb_result * res = NULL ;
struct ldb_dn * basedn ;
struct ldb_dn * conf_dn ;
struct ldb_dn * policy_dn ;
2009-11-07 23:21:26 +03:00
unsigned int i ;
int ret ;
2006-01-13 18:40:15 +03:00
/* set defaults limits in case of failure */
conn - > limits . initial_timeout = 120 ;
conn - > limits . conn_idle_time = 900 ;
conn - > limits . max_page_size = 1000 ;
2015-07-23 13:08:42 +03:00
conn - > limits . max_notifications = 5 ;
2006-01-13 18:40:15 +03:00
conn - > limits . search_timeout = 120 ;
tmp_ctx = talloc_new ( conn ) ;
if ( tmp_ctx = = NULL ) {
return - 1 ;
}
2006-11-22 03:59:34 +03:00
basedn = ldb_dn_new ( tmp_ctx , conn - > ldb , NULL ) ;
2011-03-04 12:49:47 +03:00
if ( basedn = = NULL ) {
2006-01-13 18:40:15 +03:00
goto failed ;
}
2008-09-23 22:30:06 +04:00
ret = ldb_search ( conn - > ldb , tmp_ctx , & res , basedn , LDB_SCOPE_BASE , attrs , NULL ) ;
2006-12-13 14:19:51 +03:00
if ( ret ! = LDB_SUCCESS ) {
goto failed ;
}
if ( res - > count ! = 1 ) {
2006-01-13 18:40:15 +03:00
goto failed ;
}
2006-11-22 03:59:34 +03:00
conf_dn = ldb_msg_find_attr_as_dn ( conn - > ldb , tmp_ctx , res - > msgs [ 0 ] , " configurationNamingContext " ) ;
2006-01-13 18:40:15 +03:00
if ( conf_dn = = NULL ) {
goto failed ;
}
2006-11-22 03:59:34 +03:00
policy_dn = ldb_dn_copy ( tmp_ctx , conf_dn ) ;
ldb_dn_add_child_fmt ( policy_dn , " CN=Default Query Policy,CN=Query-Policies,CN=Directory Service,CN=Windows NT,CN=Services " ) ;
2006-01-13 18:40:15 +03:00
if ( policy_dn = = NULL ) {
goto failed ;
}
2008-09-23 22:30:06 +04:00
ret = ldb_search ( conn - > ldb , tmp_ctx , & res , policy_dn , LDB_SCOPE_BASE , attrs2 , NULL ) ;
2006-12-13 14:19:51 +03:00
if ( ret ! = LDB_SUCCESS ) {
goto failed ;
}
if ( res - > count ! = 1 ) {
2006-01-13 18:40:15 +03:00
goto failed ;
}
el = ldb_msg_find_element ( res - > msgs [ 0 ] , " lDAPAdminLimits " ) ;
if ( el = = NULL ) {
goto failed ;
}
for ( i = 0 ; i < el - > num_values ; i + + ) {
char policy_name [ 256 ] ;
int policy_value , s ;
2006-03-03 11:23:57 +03:00
s = sscanf ( ( const char * ) el - > values [ i ] . data , " %255[^=]=%d " , policy_name , & policy_value ) ;
2012-09-27 05:32:28 +04:00
if ( s ! = 2 | | policy_value = = 0 )
2006-01-13 18:40:15 +03:00
continue ;
if ( strcasecmp ( " InitRecvTimeout " , policy_name ) = = 0 ) {
conn - > limits . initial_timeout = policy_value ;
continue ;
}
if ( strcasecmp ( " MaxConnIdleTime " , policy_name ) = = 0 ) {
conn - > limits . conn_idle_time = policy_value ;
continue ;
}
if ( strcasecmp ( " MaxPageSize " , policy_name ) = = 0 ) {
conn - > limits . max_page_size = policy_value ;
continue ;
}
2015-07-23 13:08:42 +03:00
if ( strcasecmp ( " MaxNotificationPerConn " , policy_name ) = = 0 ) {
conn - > limits . max_notifications = policy_value ;
continue ;
}
2006-01-13 18:40:15 +03:00
if ( strcasecmp ( " MaxQueryDuration " , policy_name ) = = 0 ) {
conn - > limits . search_timeout = policy_value ;
continue ;
}
}
return 0 ;
failed :
DEBUG ( 0 , ( " Failed to load ldap server query policies \n " ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2017-05-11 17:37:21 +03:00
static int ldapsrv_call_destructor ( struct ldapsrv_call * call )
{
if ( call - > conn = = NULL ) {
return 0 ;
}
DLIST_REMOVE ( call - > conn - > pending_calls , call ) ;
call - > conn = NULL ;
return 0 ;
}
2010-09-22 16:24:03 +04:00
static struct tevent_req * ldapsrv_process_call_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tevent_queue * call_queue ,
struct ldapsrv_call * call ) ;
static NTSTATUS ldapsrv_process_call_recv ( struct tevent_req * req ) ;
static bool ldapsrv_call_read_next ( struct ldapsrv_connection * conn ) ;
static void ldapsrv_accept_tls_done ( struct tevent_req * subreq ) ;
2010-09-07 05:57:44 +04:00
2004-09-13 14:36:59 +04:00
/*
initialise a server_context from a open socket and register a event handler
for reading from that socket
*/
2009-05-29 12:48:54 +04:00
static void ldapsrv_accept ( struct stream_connection * c ,
2010-12-01 14:18:21 +03:00
struct auth_session_info * session_info ,
bool is_privileged )
2004-09-13 14:36:59 +04:00
{
2005-06-19 11:21:18 +04:00
struct ldapsrv_service * ldapsrv_service =
2009-02-02 12:30:03 +03:00
talloc_get_type ( c - > private_data , struct ldapsrv_service ) ;
2005-06-19 13:31:34 +04:00
struct ldapsrv_connection * conn ;
2006-01-03 03:10:15 +03:00
struct cli_credentials * server_credentials ;
2006-01-10 01:12:53 +03:00
struct socket_address * socket_address ;
2006-01-03 03:10:15 +03:00
NTSTATUS status ;
2005-06-19 15:10:15 +04:00
int port ;
2010-09-22 16:24:03 +04:00
int ret ;
struct tevent_req * subreq ;
struct timeval endtime ;
2017-09-14 06:07:10 +03:00
char * errstring = NULL ;
2004-09-13 14:36:59 +04:00
2005-06-19 13:31:34 +04:00
conn = talloc_zero ( c , struct ldapsrv_connection ) ;
2005-09-08 15:26:05 +04:00
if ( ! conn ) {
stream_terminate_connection ( c , " ldapsrv_accept: out of memory " ) ;
return ;
}
2010-12-01 14:18:21 +03:00
conn - > is_privileged = is_privileged ;
2004-09-13 14:36:59 +04:00
2010-09-22 16:24:03 +04:00
conn - > sockets . send_queue = tevent_queue_create ( conn , " ldapsev send queue " ) ;
if ( conn - > sockets . send_queue = = NULL ) {
stream_terminate_connection ( c ,
" ldapsrv_accept: tevent_queue_create failed " ) ;
return ;
}
TALLOC_FREE ( c - > event . fde ) ;
ret = tstream_bsd_existing_socket ( conn ,
socket_get_fd ( c - > socket ) ,
& conn - > sockets . raw ) ;
if ( ret = = - 1 ) {
stream_terminate_connection ( c ,
" ldapsrv_accept: out of memory " ) ;
return ;
}
socket_set_flags ( c - > socket , SOCKET_FLAG_NOCLOSE ) ;
2005-06-19 13:31:34 +04:00
conn - > connection = c ;
2005-09-08 15:26:05 +04:00
conn - > service = ldapsrv_service ;
2008-01-06 00:36:33 +03:00
conn - > lp_ctx = ldapsrv_service - > task - > lp_ctx ;
2006-01-03 03:10:15 +03:00
2009-02-02 12:30:03 +03:00
c - > private_data = conn ;
2005-06-19 11:21:18 +04:00
2006-01-10 01:12:53 +03:00
socket_address = socket_get_my_addr ( c - > socket , conn ) ;
if ( ! socket_address ) {
ldapsrv_terminate_connection ( conn , " ldapsrv_accept: failed to obtain local socket address! " ) ;
return ;
}
port = socket_address - > port ;
talloc_free ( socket_address ) ;
2011-01-20 04:11:01 +03:00
if ( port = = 3268 | | port = = 3269 ) /* Global catalog */ {
2007-10-07 01:42:58 +04:00
conn - > global_catalog = true ;
2005-09-08 15:26:05 +04:00
}
2010-09-07 05:57:44 +04:00
2007-12-02 19:56:09 +03:00
server_credentials = cli_credentials_init ( conn ) ;
2006-04-29 13:20:22 +04:00
if ( ! server_credentials ) {
stream_terminate_connection ( c , " Failed to init server credentials \n " ) ;
return ;
}
2009-05-29 11:42:31 +04:00
2007-12-03 23:25:06 +03:00
cli_credentials_set_conf ( server_credentials , conn - > lp_ctx ) ;
2007-12-14 00:46:17 +03:00
status = cli_credentials_set_machine_account ( server_credentials , conn - > lp_ctx ) ;
2006-04-29 13:20:22 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
stream_terminate_connection ( c , talloc_asprintf ( conn , " Failed to obtain server credentials, perhaps a standalone server?: %s \n " , nt_errstr ( status ) ) ) ;
return ;
}
conn - > server_credentials = server_credentials ;
2005-11-10 04:41:47 +03:00
2010-12-01 15:54:38 +03:00
conn - > session_info = session_info ;
2005-10-07 15:31:45 +04:00
2011-09-27 02:56:23 +04:00
conn - > sockets . active = conn - > sockets . raw ;
2015-08-28 13:19:37 +03:00
if ( conn - > is_privileged ) {
conn - > require_strong_auth = LDAP_SERVER_REQUIRE_STRONG_AUTH_NO ;
} else {
conn - > require_strong_auth = lpcfg_ldap_server_require_strong_auth ( conn - > lp_ctx ) ;
}
2017-09-14 06:07:10 +03:00
ret = ldapsrv_backend_Init ( conn , & errstring ) ;
if ( ret ! = LDB_SUCCESS ) {
char * reason = talloc_asprintf ( conn ,
" LDB backend for LDAP Init "
" failed: %s: %s " ,
errstring , ldb_strerror ( ret ) ) ;
ldapsrv_terminate_connection ( conn , reason ) ;
2005-12-08 13:23:56 +03:00
return ;
2005-10-07 15:31:45 +04:00
}
2006-01-13 18:40:15 +03:00
/* load limits from the conf partition */
ldapsrv_load_limits ( conn ) ; /* should we fail on error ? */
2005-10-07 15:31:45 +04:00
2006-01-13 03:38:35 +03:00
/* register the server */
2005-07-10 05:08:10 +04:00
irpc_add_name ( c - > msg_ctx , " ldap_server " ) ;
2006-01-13 03:38:35 +03:00
2015-07-23 13:08:42 +03:00
DLIST_ADD_END ( ldapsrv_service - > connections , conn ) ;
2011-01-20 04:11:01 +03:00
if ( port ! = 636 & & port ! = 3269 ) {
2010-09-22 16:24:03 +04:00
ldapsrv_call_read_next ( conn ) ;
return ;
}
endtime = timeval_current_ofs ( conn - > limits . conn_idle_time , 0 ) ;
subreq = tstream_tls_accept_send ( conn ,
conn - > connection - > event . ctx ,
conn - > sockets . raw ,
conn - > service - > tls_params ) ;
if ( subreq = = NULL ) {
ldapsrv_terminate_connection ( conn , " ldapsrv_accept: "
" no memory for tstream_tls_accept_send " ) ;
return ;
}
tevent_req_set_endtime ( subreq ,
conn - > connection - > event . ctx ,
endtime ) ;
tevent_req_set_callback ( subreq , ldapsrv_accept_tls_done , conn ) ;
}
static void ldapsrv_accept_tls_done ( struct tevent_req * subreq )
{
struct ldapsrv_connection * conn =
tevent_req_callback_data ( subreq ,
struct ldapsrv_connection ) ;
int ret ;
int sys_errno ;
ret = tstream_tls_accept_recv ( subreq , & sys_errno ,
conn , & conn - > sockets . tls ) ;
TALLOC_FREE ( subreq ) ;
if ( ret = = - 1 ) {
const char * reason ;
reason = talloc_asprintf ( conn , " ldapsrv_accept_tls_loop: "
" tstream_tls_accept_recv() - %d:%s " ,
sys_errno , strerror ( sys_errno ) ) ;
if ( ! reason ) {
reason = " ldapsrv_accept_tls_loop: "
" tstream_tls_accept_recv() - failed " ;
}
ldapsrv_terminate_connection ( conn , reason ) ;
return ;
}
2010-09-22 16:24:03 +04:00
2010-09-22 16:24:03 +04:00
conn - > sockets . active = conn - > sockets . tls ;
ldapsrv_call_read_next ( conn ) ;
}
2010-09-22 16:24:03 +04:00
2010-09-22 16:24:03 +04:00
static void ldapsrv_call_read_done ( struct tevent_req * subreq ) ;
static bool ldapsrv_call_read_next ( struct ldapsrv_connection * conn )
{
struct tevent_req * subreq ;
2015-07-23 13:08:42 +03:00
if ( conn - > pending_calls ! = NULL ) {
conn - > limits . endtime = timeval_zero ( ) ;
ldapsrv_notification_retry_setup ( conn - > service , false ) ;
} else if ( timeval_is_zero ( & conn - > limits . endtime ) ) {
2010-09-22 16:24:03 +04:00
conn - > limits . endtime =
timeval_current_ofs ( conn - > limits . initial_timeout , 0 ) ;
} else {
conn - > limits . endtime =
timeval_current_ofs ( conn - > limits . conn_idle_time , 0 ) ;
}
2015-07-23 13:06:11 +03:00
if ( conn - > sockets . read_req ! = NULL ) {
return true ;
}
2010-09-22 16:24:03 +04:00
/*
2017-03-07 17:29:18 +03:00
* The minimum size of a LDAP pdu is 7 bytes
2010-09-22 16:24:03 +04:00
*
* dumpasn1 - hh ldap - unbind - min . dat
*
* < 30 05 02 01 09 42 00 >
* 0 5 : SEQUENCE {
* < 02 01 09 >
* 2 1 : INTEGER 9
* < 42 00 >
* 5 0 : [ APPLICATION 2 ]
* : Error : Object has zero length .
* : }
*
* dumpasn1 - hh ldap - unbind - windows . dat
*
* < 30 84 00 00 00 05 02 01 09 42 00 >
* 0 5 : SEQUENCE {
* < 02 01 09 >
* 6 1 : INTEGER 9
* < 42 00 >
* 9 0 : [ APPLICATION 2 ]
* : Error : Object has zero length .
* : }
*
* This means using an initial read size
* of 7 is ok .
*/
subreq = tstream_read_pdu_blob_send ( conn ,
conn - > connection - > event . ctx ,
conn - > sockets . active ,
7 , /* initial_read_size */
ldap_full_packet ,
conn ) ;
if ( subreq = = NULL ) {
ldapsrv_terminate_connection ( conn , " ldapsrv_call_read_next: "
" no memory for tstream_read_pdu_blob_send " ) ;
return false ;
}
2015-07-23 13:08:42 +03:00
if ( ! timeval_is_zero ( & conn - > limits . endtime ) ) {
2018-05-22 14:25:41 +03:00
bool ok ;
ok = tevent_req_set_endtime ( subreq ,
conn - > connection - > event . ctx ,
conn - > limits . endtime ) ;
if ( ! ok ) {
ldapsrv_terminate_connection (
conn ,
" ldapsrv_call_read_next: "
" no memory for tevent_req_set_endtime " ) ;
return false ;
}
2015-07-23 13:08:42 +03:00
}
2010-09-22 16:24:03 +04:00
tevent_req_set_callback ( subreq , ldapsrv_call_read_done , conn ) ;
2015-07-23 13:06:11 +03:00
conn - > sockets . read_req = subreq ;
2010-09-22 16:24:03 +04:00
return true ;
}
static void ldapsrv_call_process_done ( struct tevent_req * subreq ) ;
static void ldapsrv_call_read_done ( struct tevent_req * subreq )
{
struct ldapsrv_connection * conn =
tevent_req_callback_data ( subreq ,
struct ldapsrv_connection ) ;
NTSTATUS status ;
struct ldapsrv_call * call ;
struct asn1_data * asn1 ;
DATA_BLOB blob ;
2015-07-23 13:06:11 +03:00
conn - > sockets . read_req = NULL ;
2010-09-22 16:24:03 +04:00
call = talloc_zero ( conn , struct ldapsrv_call ) ;
if ( ! call ) {
ldapsrv_terminate_connection ( conn , " no memory " ) ;
return ;
}
2017-05-11 17:37:21 +03:00
talloc_set_destructor ( call , ldapsrv_call_destructor ) ;
2010-09-22 16:24:03 +04:00
call - > conn = conn ;
status = tstream_read_pdu_blob_recv ( subreq ,
call ,
& blob ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
const char * reason ;
reason = talloc_asprintf ( call , " ldapsrv_call_loop: "
" tstream_read_pdu_blob_recv() - %s " ,
nt_errstr ( status ) ) ;
if ( ! reason ) {
reason = nt_errstr ( status ) ;
}
ldapsrv_terminate_connection ( conn , reason ) ;
return ;
}
asn1 = asn1_init ( call ) ;
if ( asn1 = = NULL ) {
ldapsrv_terminate_connection ( conn , " no memory " ) ;
return ;
}
call - > request = talloc ( call , struct ldap_message ) ;
if ( call - > request = = NULL ) {
ldapsrv_terminate_connection ( conn , " no memory " ) ;
return ;
}
if ( ! asn1_load ( asn1 , blob ) ) {
ldapsrv_terminate_connection ( conn , " asn1_load failed " ) ;
return ;
}
status = ldap_decode ( asn1 , samba_ldap_control_handlers ( ) ,
call - > request ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
ldapsrv_terminate_connection ( conn , nt_errstr ( status ) ) ;
return ;
}
data_blob_free ( & blob ) ;
/* queue the call in the global queue */
subreq = ldapsrv_process_call_send ( call ,
conn - > connection - > event . ctx ,
conn - > service - > call_queue ,
call ) ;
if ( subreq = = NULL ) {
ldapsrv_terminate_connection ( conn , " ldapsrv_process_call_send failed " ) ;
return ;
}
tevent_req_set_callback ( subreq , ldapsrv_call_process_done , call ) ;
conn - > active_call = subreq ;
}
2017-05-11 17:51:15 +03:00
static void ldapsrv_call_wait_done ( struct tevent_req * subreq ) ;
static void ldapsrv_call_writev_start ( struct ldapsrv_call * call ) ;
2010-09-22 16:24:03 +04:00
static void ldapsrv_call_writev_done ( struct tevent_req * subreq ) ;
static void ldapsrv_call_process_done ( struct tevent_req * subreq )
{
struct ldapsrv_call * call =
tevent_req_callback_data ( subreq ,
struct ldapsrv_call ) ;
struct ldapsrv_connection * conn = call - > conn ;
NTSTATUS status ;
conn - > active_call = NULL ;
status = ldapsrv_process_call_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
ldapsrv_terminate_connection ( conn , nt_errstr ( status ) ) ;
return ;
}
2017-05-11 17:51:15 +03:00
if ( call - > wait_send ! = NULL ) {
subreq = call - > wait_send ( call ,
conn - > connection - > event . ctx ,
call - > wait_private ) ;
if ( subreq = = NULL ) {
ldapsrv_terminate_connection ( conn ,
" ldapsrv_call_process_done: "
" call->wait_send - no memory " ) ;
return ;
}
tevent_req_set_callback ( subreq ,
ldapsrv_call_wait_done ,
call ) ;
conn - > active_call = subreq ;
return ;
}
ldapsrv_call_writev_start ( call ) ;
}
static void ldapsrv_call_wait_done ( struct tevent_req * subreq )
{
struct ldapsrv_call * call =
tevent_req_callback_data ( subreq ,
struct ldapsrv_call ) ;
struct ldapsrv_connection * conn = call - > conn ;
NTSTATUS status ;
conn - > active_call = NULL ;
status = call - > wait_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
const char * reason ;
reason = talloc_asprintf ( call , " ldapsrv_call_wait_done: "
" call->wait_recv() - %s " ,
nt_errstr ( status ) ) ;
if ( reason = = NULL ) {
reason = nt_errstr ( status ) ;
}
ldapsrv_terminate_connection ( conn , reason ) ;
return ;
}
ldapsrv_call_writev_start ( call ) ;
}
static void ldapsrv_call_writev_start ( struct ldapsrv_call * call )
{
struct ldapsrv_connection * conn = call - > conn ;
2019-04-04 07:25:30 +03:00
struct ldapsrv_reply * reply = NULL ;
2017-05-11 17:51:15 +03:00
struct tevent_req * subreq = NULL ;
2019-04-04 07:25:30 +03:00
size_t length = 0 ;
size_t i ;
2017-05-11 17:51:15 +03:00
2019-04-04 07:25:30 +03:00
call - > iov_count = 0 ;
2010-09-22 16:24:03 +04:00
2019-04-04 07:25:30 +03:00
/* build all the replies into an IOV (no copy) */
for ( reply = call - > replies ;
reply ! = NULL ;
reply = reply - > next ) {
/*
* Overflow is harmless here , just used below to
* decide if to read or write
*/
length + = reply - > blob . length ;
2010-09-22 16:24:03 +04:00
2019-04-04 07:25:30 +03:00
/*
* At worst an overflow would mean we send less
* replies
*/
call - > iov_count + + ;
2010-09-22 16:24:03 +04:00
}
2019-04-04 07:25:30 +03:00
if ( length = = 0 ) {
2015-07-23 13:08:42 +03:00
if ( ! call - > notification . busy ) {
TALLOC_FREE ( call ) ;
}
2010-09-22 16:24:03 +04:00
ldapsrv_call_read_next ( conn ) ;
return ;
}
2019-04-04 07:25:30 +03:00
/* Cap call->iov_count at IOV_MAX */
call - > iov_count = MIN ( call - > iov_count , IOV_MAX ) ;
call - > out_iov = talloc_array ( call ,
struct iovec ,
call - > iov_count ) ;
if ( ! call - > out_iov ) {
/* This is not ideal */
ldapsrv_terminate_connection ( conn ,
" failed to allocate "
" iovec array " ) ;
return ;
}
/* We may have had to cap the number of replies at IOV_MAX */
for ( i = 0 ;
i < call - > iov_count & & call - > replies ! = NULL ;
i + + ) {
reply = call - > replies ;
call - > out_iov [ i ] . iov_base = reply - > blob . data ;
call - > out_iov [ i ] . iov_len = reply - > blob . length ;
/* Keep only the ASN.1 encoded data */
talloc_steal ( call - > out_iov , reply - > blob . data ) ;
DLIST_REMOVE ( call - > replies , reply ) ;
TALLOC_FREE ( reply ) ;
}
if ( i > call - > iov_count ) {
/* This is not ideal, but also (essentially) impossible */
ldapsrv_terminate_connection ( conn ,
" call list ended "
" before iov_count " ) ;
return ;
}
2010-09-22 16:24:03 +04:00
subreq = tstream_writev_queue_send ( call ,
conn - > connection - > event . ctx ,
conn - > sockets . active ,
conn - > sockets . send_queue ,
2019-04-04 07:25:30 +03:00
call - > out_iov , call - > iov_count ) ;
2010-09-22 16:24:03 +04:00
if ( subreq = = NULL ) {
ldapsrv_terminate_connection ( conn , " stream_writev_queue_send failed " ) ;
return ;
}
tevent_req_set_callback ( subreq , ldapsrv_call_writev_done , call ) ;
}
static void ldapsrv_call_postprocess_done ( struct tevent_req * subreq ) ;
static void ldapsrv_call_writev_done ( struct tevent_req * subreq )
{
struct ldapsrv_call * call =
tevent_req_callback_data ( subreq ,
struct ldapsrv_call ) ;
struct ldapsrv_connection * conn = call - > conn ;
int sys_errno ;
int rc ;
rc = tstream_writev_queue_recv ( subreq , & sys_errno ) ;
TALLOC_FREE ( subreq ) ;
2019-04-04 07:25:30 +03:00
/* This releases the ASN.1 encoded packets from memory */
TALLOC_FREE ( call - > out_iov ) ;
2010-09-22 16:24:03 +04:00
if ( rc = = - 1 ) {
const char * reason ;
reason = talloc_asprintf ( call , " ldapsrv_call_writev_done: "
" tstream_writev_queue_recv() - %d:%s " ,
sys_errno , strerror ( sys_errno ) ) ;
if ( reason = = NULL ) {
reason = " ldapsrv_call_writev_done: "
" tstream_writev_queue_recv() failed " ;
}
ldapsrv_terminate_connection ( conn , reason ) ;
return ;
}
if ( call - > postprocess_send ) {
subreq = call - > postprocess_send ( call ,
conn - > connection - > event . ctx ,
call - > postprocess_private ) ;
if ( subreq = = NULL ) {
ldapsrv_terminate_connection ( conn , " ldapsrv_call_writev_done: "
" call->postprocess_send - no memory " ) ;
return ;
}
tevent_req_set_callback ( subreq ,
ldapsrv_call_postprocess_done ,
call ) ;
return ;
}
2019-04-04 07:25:30 +03:00
/* Perhaps still some more to send */
if ( call - > replies ! = NULL ) {
ldapsrv_call_writev_start ( call ) ;
return ;
}
2015-07-23 13:08:42 +03:00
if ( ! call - > notification . busy ) {
TALLOC_FREE ( call ) ;
}
2010-09-22 16:24:03 +04:00
ldapsrv_call_read_next ( conn ) ;
}
static void ldapsrv_call_postprocess_done ( struct tevent_req * subreq )
{
struct ldapsrv_call * call =
tevent_req_callback_data ( subreq ,
struct ldapsrv_call ) ;
struct ldapsrv_connection * conn = call - > conn ;
NTSTATUS status ;
status = call - > postprocess_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
const char * reason ;
reason = talloc_asprintf ( call , " ldapsrv_call_postprocess_done: "
" call->postprocess_recv() - %s " ,
nt_errstr ( status ) ) ;
if ( reason = = NULL ) {
reason = nt_errstr ( status ) ;
}
ldapsrv_terminate_connection ( conn , reason ) ;
return ;
}
TALLOC_FREE ( call ) ;
ldapsrv_call_read_next ( conn ) ;
}
2015-07-23 13:08:42 +03:00
static void ldapsrv_notification_retry_done ( struct tevent_req * subreq ) ;
void ldapsrv_notification_retry_setup ( struct ldapsrv_service * service , bool force )
{
struct ldapsrv_connection * conn = NULL ;
struct timeval retry ;
size_t num_pending = 0 ;
size_t num_active = 0 ;
if ( force ) {
TALLOC_FREE ( service - > notification . retry ) ;
service - > notification . generation + = 1 ;
}
if ( service - > notification . retry ! = NULL ) {
return ;
}
for ( conn = service - > connections ; conn ! = NULL ; conn = conn - > next ) {
if ( conn - > pending_calls = = NULL ) {
continue ;
}
num_pending + = 1 ;
if ( conn - > pending_calls - > notification . generation ! =
service - > notification . generation )
{
num_active + = 1 ;
}
}
if ( num_pending = = 0 ) {
return ;
}
if ( num_active ! = 0 ) {
retry = timeval_current_ofs ( 0 , 100 ) ;
} else {
retry = timeval_current_ofs ( 5 , 0 ) ;
}
service - > notification . retry = tevent_wakeup_send ( service ,
service - > task - > event_ctx ,
retry ) ;
if ( service - > notification . retry = = NULL ) {
/* retry later */
return ;
}
tevent_req_set_callback ( service - > notification . retry ,
ldapsrv_notification_retry_done ,
service ) ;
}
static void ldapsrv_notification_retry_done ( struct tevent_req * subreq )
{
struct ldapsrv_service * service =
tevent_req_callback_data ( subreq ,
struct ldapsrv_service ) ;
struct ldapsrv_connection * conn = NULL ;
struct ldapsrv_connection * conn_next = NULL ;
bool ok ;
service - > notification . retry = NULL ;
ok = tevent_wakeup_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! ok ) {
/* ignore */
}
for ( conn = service - > connections ; conn ! = NULL ; conn = conn_next ) {
struct ldapsrv_call * call = conn - > pending_calls ;
conn_next = conn - > next ;
if ( conn - > pending_calls = = NULL ) {
continue ;
}
if ( conn - > active_call ! = NULL ) {
continue ;
}
DLIST_DEMOTE ( conn - > pending_calls , call ) ;
call - > notification . generation =
service - > notification . generation ;
/* queue the call in the global queue */
subreq = ldapsrv_process_call_send ( call ,
conn - > connection - > event . ctx ,
conn - > service - > call_queue ,
call ) ;
if ( subreq = = NULL ) {
ldapsrv_terminate_connection ( conn ,
" ldapsrv_process_call_send failed " ) ;
continue ;
}
tevent_req_set_callback ( subreq , ldapsrv_call_process_done , call ) ;
conn - > active_call = subreq ;
}
ldapsrv_notification_retry_setup ( service , false ) ;
}
2010-09-22 16:24:03 +04:00
struct ldapsrv_process_call_state {
struct ldapsrv_call * call ;
} ;
static void ldapsrv_process_call_trigger ( struct tevent_req * req ,
void * private_data ) ;
static struct tevent_req * ldapsrv_process_call_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tevent_queue * call_queue ,
struct ldapsrv_call * call )
{
struct tevent_req * req ;
struct ldapsrv_process_call_state * state ;
bool ok ;
req = tevent_req_create ( mem_ctx , & state ,
struct ldapsrv_process_call_state ) ;
if ( req = = NULL ) {
return req ;
}
state - > call = call ;
ok = tevent_queue_add ( call_queue , ev , req ,
ldapsrv_process_call_trigger , NULL ) ;
if ( ! ok ) {
2011-06-19 23:10:01 +04:00
tevent_req_oom ( req ) ;
2010-09-22 16:24:03 +04:00
return tevent_req_post ( req , ev ) ;
}
return req ;
}
static void ldapsrv_process_call_trigger ( struct tevent_req * req ,
void * private_data )
{
struct ldapsrv_process_call_state * state =
tevent_req_data ( req ,
struct ldapsrv_process_call_state ) ;
NTSTATUS status ;
/* make the call */
status = ldapsrv_do_call ( state - > call ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return ;
}
tevent_req_done ( req ) ;
}
static NTSTATUS ldapsrv_process_call_recv ( struct tevent_req * req )
{
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
return status ;
}
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
2004-09-13 14:36:59 +04:00
}
2009-05-29 12:48:54 +04:00
static void ldapsrv_accept_nonpriv ( struct stream_connection * c )
{
struct ldapsrv_service * ldapsrv_service = talloc_get_type_abort (
c - > private_data , struct ldapsrv_service ) ;
struct auth_session_info * session_info ;
NTSTATUS status ;
status = auth_anonymous_session_info (
2010-04-09 11:18:53 +04:00
c , ldapsrv_service - > task - > lp_ctx , & session_info ) ;
2009-05-29 12:48:54 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
stream_terminate_connection ( c , " failed to setup anonymous "
" session info " ) ;
return ;
}
2010-12-01 14:18:21 +03:00
ldapsrv_accept ( c , session_info , false ) ;
2009-05-29 12:48:54 +04:00
}
static const struct stream_server_ops ldap_stream_nonpriv_ops = {
. name = " ldap " ,
. accept_connection = ldapsrv_accept_nonpriv ,
. recv_handler = ldapsrv_recv ,
. send_handler = ldapsrv_send ,
} ;
2009-06-18 08:55:31 +04:00
/* The feature removed behind an #ifdef until we can do it properly
* with an EXTERNAL bind . */
2009-06-19 09:29:42 +04:00
# define WITH_LDAPI_PRIV_SOCKET
2009-06-18 08:55:31 +04:00
# ifdef WITH_LDAPI_PRIV_SOCKET
2009-05-29 12:48:54 +04:00
static void ldapsrv_accept_priv ( struct stream_connection * c )
{
struct ldapsrv_service * ldapsrv_service = talloc_get_type_abort (
c - > private_data , struct ldapsrv_service ) ;
struct auth_session_info * session_info ;
2009-10-25 09:19:03 +03:00
session_info = system_session ( ldapsrv_service - > task - > lp_ctx ) ;
if ( ! session_info ) {
2009-05-29 12:48:54 +04:00
stream_terminate_connection ( c , " failed to setup system "
" session info " ) ;
return ;
}
2010-12-01 14:18:21 +03:00
ldapsrv_accept ( c , session_info , true ) ;
2009-05-29 12:48:54 +04:00
}
static const struct stream_server_ops ldap_stream_priv_ops = {
2005-01-14 04:32:56 +03:00
. name = " ldap " ,
2009-05-29 12:48:54 +04:00
. accept_connection = ldapsrv_accept_priv ,
2005-01-14 04:32:56 +03:00
. recv_handler = ldapsrv_recv ,
. send_handler = ldapsrv_send ,
} ;
2009-06-18 08:55:31 +04:00
# endif
2010-11-15 02:12:22 +03:00
2005-01-30 03:54:57 +03:00
/*
add a socket address to the list of events , one event per port
*/
2010-11-15 02:12:22 +03:00
static NTSTATUS add_socket ( struct task_server * task ,
2010-07-16 08:32:42 +04:00
struct loadparm_context * lp_ctx ,
2005-06-19 13:31:34 +04:00
const struct model_ops * model_ops ,
2005-01-30 03:54:57 +03:00
const char * address , struct ldapsrv_service * ldap_service )
2004-09-13 14:36:59 +04:00
{
2005-01-30 03:54:57 +03:00
uint16_t port = 389 ;
NTSTATUS status ;
2006-12-13 14:19:51 +03:00
struct ldb_context * ldb ;
2005-01-30 03:54:57 +03:00
2010-11-15 02:12:22 +03:00
status = stream_setup_socket ( task , task - > event_ctx , lp_ctx ,
2009-05-29 12:48:54 +04:00
model_ops , & ldap_stream_nonpriv_ops ,
2011-05-12 14:36:33 +04:00
" ip " , address , & port ,
2010-07-16 08:32:42 +04:00
lpcfg_socket_options ( lp_ctx ) ,
2017-09-14 22:09:23 +03:00
ldap_service , task - > process_context ) ;
2005-06-19 11:21:18 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " ldapsrv failed to bind to %s:%u - %s \n " ,
address , port , nt_errstr ( status ) ) ) ;
2010-06-28 11:57:33 +04:00
return status ;
2005-06-19 11:21:18 +04:00
}
2005-01-30 03:54:57 +03:00
2010-09-22 16:24:03 +04:00
if ( tstream_tls_params_enabled ( ldap_service - > tls_params ) ) {
2005-06-19 13:31:34 +04:00
/* add ldaps server */
port = 636 ;
2010-11-15 02:12:22 +03:00
status = stream_setup_socket ( task , task - > event_ctx , lp_ctx ,
2009-05-29 12:48:54 +04:00
model_ops ,
& ldap_stream_nonpriv_ops ,
2011-05-12 14:36:33 +04:00
" ip " , address , & port ,
2010-07-16 08:32:42 +04:00
lpcfg_socket_options ( lp_ctx ) ,
2017-09-14 22:09:23 +03:00
ldap_service ,
task - > process_context ) ;
2005-06-19 13:31:34 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " ldapsrv failed to bind to %s:%u - %s \n " ,
address , port , nt_errstr ( status ) ) ) ;
2010-06-28 11:57:33 +04:00
return status ;
2005-06-19 13:31:34 +04:00
}
2005-06-19 11:21:18 +04:00
}
2005-06-19 13:31:34 +04:00
2008-07-16 05:11:25 +04:00
/* Load LDAP database, but only to read our settings */
2018-04-11 21:41:30 +03:00
ldb = samdb_connect ( ldap_service ,
ldap_service - > task - > event_ctx ,
lp_ctx ,
system_session ( lp_ctx ) ,
NULL ,
0 ) ;
2006-12-13 14:19:51 +03:00
if ( ! ldb ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
2009-05-29 11:42:31 +04:00
2008-01-03 13:40:24 +03:00
if ( samdb_is_gc ( ldb ) ) {
2005-10-17 15:32:20 +04:00
port = 3268 ;
2010-11-15 02:12:22 +03:00
status = stream_setup_socket ( task , task - > event_ctx , lp_ctx ,
2009-05-29 12:48:54 +04:00
model_ops ,
& ldap_stream_nonpriv_ops ,
2011-05-12 14:36:33 +04:00
" ip " , address , & port ,
2010-07-16 08:32:42 +04:00
lpcfg_socket_options ( lp_ctx ) ,
2017-09-14 22:09:23 +03:00
ldap_service ,
task - > process_context ) ;
2005-10-17 15:32:20 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " ldapsrv failed to bind to %s:%u - %s \n " ,
address , port , nt_errstr ( status ) ) ) ;
2010-06-28 11:57:33 +04:00
return status ;
2005-10-17 15:32:20 +04:00
}
2011-01-20 04:11:01 +03:00
if ( tstream_tls_params_enabled ( ldap_service - > tls_params ) ) {
/* add ldaps server for the global catalog */
port = 3269 ;
status = stream_setup_socket ( task , task - > event_ctx , lp_ctx ,
model_ops ,
& ldap_stream_nonpriv_ops ,
2011-05-12 14:36:33 +04:00
" ip " , address , & port ,
2011-01-20 04:11:01 +03:00
lpcfg_socket_options ( lp_ctx ) ,
2017-09-14 22:09:23 +03:00
ldap_service ,
task - > process_context ) ;
2011-01-20 04:11:01 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " ldapsrv failed to bind to %s:%u - %s \n " ,
address , port , nt_errstr ( status ) ) ) ;
return status ;
}
}
2005-10-17 15:32:20 +04:00
}
2011-01-20 04:11:01 +03:00
/* And once we are bound, free the temporary ldb, it will
2008-07-16 05:11:25 +04:00
* connect again on each incoming LDAP connection */
2009-10-23 07:27:00 +04:00
talloc_unlink ( ldap_service , ldb ) ;
2008-07-16 05:11:25 +04:00
2010-06-28 11:57:33 +04:00
return NT_STATUS_OK ;
2004-09-13 14:36:59 +04:00
}
2005-01-30 03:54:57 +03:00
/*
open the ldap server sockets
*/
2018-08-23 00:35:52 +03:00
static NTSTATUS ldapsrv_task_init ( struct task_server * task )
2005-01-30 03:54:57 +03:00
{
2009-06-18 08:55:31 +04:00
char * ldapi_path ;
# ifdef WITH_LDAPI_PRIV_SOCKET
char * priv_dir ;
# endif
2010-09-22 16:24:03 +04:00
const char * dns_host_name ;
2005-01-30 03:54:57 +03:00
struct ldapsrv_service * ldap_service ;
NTSTATUS status ;
2004-09-13 14:36:59 +04:00
2010-07-16 08:32:42 +04:00
switch ( lpcfg_server_role ( task - > lp_ctx ) ) {
2007-09-22 16:57:17 +04:00
case ROLE_STANDALONE :
2009-09-19 05:05:55 +04:00
task_server_terminate ( task , " ldap_server: no LDAP server required in standalone configuration " ,
false ) ;
2018-08-23 00:35:52 +03:00
return NT_STATUS_INVALID_DOMAIN_ROLE ;
2007-09-22 16:57:17 +04:00
case ROLE_DOMAIN_MEMBER :
2009-09-19 05:05:55 +04:00
task_server_terminate ( task , " ldap_server: no LDAP server required in member server configuration " ,
false ) ;
2018-08-23 00:35:52 +03:00
return NT_STATUS_INVALID_DOMAIN_ROLE ;
2012-06-10 16:08:20 +04:00
case ROLE_ACTIVE_DIRECTORY_DC :
2007-09-22 16:57:17 +04:00
/* Yes, we want an LDAP server */
break ;
}
2006-03-09 20:48:41 +03:00
task_server_set_title ( task , " task[ldapsrv] " ) ;
2005-06-19 11:21:18 +04:00
ldap_service = talloc_zero ( task , struct ldapsrv_service ) ;
2018-08-23 00:35:52 +03:00
if ( ldap_service = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto failed ;
}
2005-01-30 03:54:57 +03:00
2008-01-06 00:36:33 +03:00
ldap_service - > task = task ;
2010-09-22 16:24:03 +04:00
dns_host_name = talloc_asprintf ( ldap_service , " %s.%s " ,
lpcfg_netbios_name ( task - > lp_ctx ) ,
lpcfg_dnsdomain ( task - > lp_ctx ) ) ;
2018-08-23 00:35:52 +03:00
if ( dns_host_name = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto failed ;
}
2010-09-22 16:24:03 +04:00
status = tstream_tls_params_server ( ldap_service ,
dns_host_name ,
lpcfg_tls_enabled ( task - > lp_ctx ) ,
lpcfg_tls_keyfile ( ldap_service , task - > lp_ctx ) ,
lpcfg_tls_certfile ( ldap_service , task - > lp_ctx ) ,
lpcfg_tls_cafile ( ldap_service , task - > lp_ctx ) ,
lpcfg_tls_crlfile ( ldap_service , task - > lp_ctx ) ,
lpcfg_tls_dhpfile ( ldap_service , task - > lp_ctx ) ,
2015-07-20 02:22:46 +03:00
lpcfg_tls_priority ( task - > lp_ctx ) ,
2010-09-22 16:24:03 +04:00
& ldap_service - > tls_params ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2012-04-03 15:55:08 +04:00
DEBUG ( 0 , ( " ldapsrv failed tstream_tls_params_server - %s \n " ,
2010-09-22 16:24:03 +04:00
nt_errstr ( status ) ) ) ;
goto failed ;
}
ldap_service - > call_queue = tevent_queue_create ( ldap_service , " ldapsrv_call_queue " ) ;
2018-08-23 00:35:52 +03:00
if ( ldap_service - > call_queue = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto failed ;
}
2005-01-30 03:54:57 +03:00
2010-07-16 08:32:42 +04:00
if ( lpcfg_interfaces ( task - > lp_ctx ) & & lpcfg_bind_interfaces_only ( task - > lp_ctx ) ) {
2007-12-12 00:23:14 +03:00
struct interface * ifaces ;
int num_interfaces ;
2005-01-30 03:54:57 +03:00
int i ;
2011-06-02 09:40:28 +04:00
load_interface_list ( task , task - > lp_ctx , & ifaces ) ;
2011-05-02 09:57:19 +04:00
num_interfaces = iface_list_count ( ifaces ) ;
2007-12-12 00:23:14 +03:00
2005-01-30 03:54:57 +03:00
/* We have been given an interfaces line, and been
told to only bind to those interfaces . Create a
socket per interface and bind to only these .
*/
for ( i = 0 ; i < num_interfaces ; i + + ) {
2011-05-02 09:57:19 +04:00
const char * address = iface_list_n_ip ( ifaces , i ) ;
2017-09-18 04:05:24 +03:00
status = add_socket ( task , task - > lp_ctx , task - > model_ops ,
address , ldap_service ) ;
2005-06-19 11:21:18 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) goto failed ;
2005-01-30 03:54:57 +03:00
}
} else {
2014-02-27 13:28:23 +04:00
char * * wcard ;
2017-12-07 19:43:08 +03:00
size_t i ;
size_t num_binds = 0 ;
2014-02-27 13:28:23 +04:00
wcard = iface_list_wildcard ( task ) ;
2011-05-12 14:35:02 +04:00
if ( wcard = = NULL ) {
DEBUG ( 0 , ( " No wildcard addresses available \n " ) ) ;
2018-08-23 00:35:52 +03:00
status = NT_STATUS_UNSUCCESSFUL ;
2011-05-12 14:35:02 +04:00
goto failed ;
}
for ( i = 0 ; wcard [ i ] ; i + + ) {
2017-09-18 04:05:24 +03:00
status = add_socket ( task , task - > lp_ctx , task - > model_ops ,
wcard [ i ] , ldap_service ) ;
2014-06-05 23:32:30 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
num_binds + + ;
}
2011-05-12 14:35:02 +04:00
}
talloc_free ( wcard ) ;
2014-06-05 23:32:30 +04:00
if ( num_binds = = 0 ) {
2018-08-23 00:35:52 +03:00
status = NT_STATUS_UNSUCCESSFUL ;
2014-06-05 23:32:30 +04:00
goto failed ;
}
2005-01-30 03:54:57 +03:00
}
2011-04-29 06:47:11 +04:00
ldapi_path = lpcfg_private_path ( ldap_service , task - > lp_ctx , " ldapi " ) ;
2007-11-10 07:31:26 +03:00
if ( ! ldapi_path ) {
2018-08-23 00:35:52 +03:00
status = NT_STATUS_UNSUCCESSFUL ;
2007-11-10 07:31:26 +03:00
goto failed ;
}
2010-11-15 02:12:22 +03:00
status = stream_setup_socket ( task , task - > event_ctx , task - > lp_ctx ,
2017-09-18 04:05:24 +03:00
task - > model_ops , & ldap_stream_nonpriv_ops ,
2007-12-06 18:54:34 +03:00
" unix " , ldapi_path , NULL ,
2010-07-16 08:32:42 +04:00
lpcfg_socket_options ( task - > lp_ctx ) ,
2017-09-14 22:09:23 +03:00
ldap_service , task - > process_context ) ;
2007-11-10 07:31:26 +03:00
talloc_free ( ldapi_path ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " ldapsrv failed to bind to %s - %s \n " ,
ldapi_path , nt_errstr ( status ) ) ) ;
}
2009-06-18 08:55:31 +04:00
# ifdef WITH_LDAPI_PRIV_SOCKET
2011-04-29 06:47:11 +04:00
priv_dir = lpcfg_private_path ( ldap_service , task - > lp_ctx , " ldap_priv " ) ;
2009-05-29 12:48:54 +04:00
if ( priv_dir = = NULL ) {
2018-08-23 00:35:52 +03:00
status = NT_STATUS_UNSUCCESSFUL ;
2009-05-29 12:48:54 +04:00
goto failed ;
}
/*
* Make sure the directory for the privileged ldapi socket exists , and
* is of the correct permissions
*/
2014-07-27 21:18:09 +04:00
if ( ! directory_create_or_exist ( priv_dir , 0750 ) ) {
2009-05-29 12:48:54 +04:00
task_server_terminate ( task , " Cannot create ldap "
2009-09-19 05:05:55 +04:00
" privileged ldapi directory " , true ) ;
2018-08-23 00:35:52 +03:00
return NT_STATUS_UNSUCCESSFUL ;
2009-05-29 12:48:54 +04:00
}
ldapi_path = talloc_asprintf ( ldap_service , " %s/ldapi " , priv_dir ) ;
talloc_free ( priv_dir ) ;
if ( ldapi_path = = NULL ) {
2018-08-23 00:35:52 +03:00
status = NT_STATUS_NO_MEMORY ;
2009-05-29 12:48:54 +04:00
goto failed ;
}
2010-11-15 02:12:22 +03:00
status = stream_setup_socket ( task , task - > event_ctx , task - > lp_ctx ,
2017-09-18 04:05:24 +03:00
task - > model_ops , & ldap_stream_priv_ops ,
2009-05-29 12:48:54 +04:00
" unix " , ldapi_path , NULL ,
2010-07-16 08:32:42 +04:00
lpcfg_socket_options ( task - > lp_ctx ) ,
2017-09-14 22:09:23 +03:00
ldap_service ,
task - > process_context ) ;
2009-05-29 12:48:54 +04:00
talloc_free ( ldapi_path ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " ldapsrv failed to bind to %s - %s \n " ,
ldapi_path , nt_errstr ( status ) ) ) ;
}
2009-06-18 08:55:31 +04:00
# endif
2013-05-27 14:10:57 +04:00
/* register the server */
irpc_add_name ( task - > msg_ctx , " ldap_server " ) ;
2019-05-08 03:40:48 +03:00
task - > private_data = ldap_service ;
2018-08-23 00:35:52 +03:00
return NT_STATUS_OK ;
2005-06-19 11:21:18 +04:00
failed :
2009-09-19 05:05:55 +04:00
task_server_terminate ( task , " Failed to startup ldap server task " , true ) ;
2018-08-23 00:35:52 +03:00
return status ;
2005-06-19 11:21:18 +04:00
}
2019-05-08 03:40:48 +03:00
/*
* Open a database to be later used by LDB wrap code ( although it should be
* plumbed through correctly eventually ) .
*/
static void ldapsrv_post_fork ( struct task_server * task , struct process_details * pd )
{
struct ldapsrv_service * ldap_service =
talloc_get_type_abort ( task - > private_data , struct ldapsrv_service ) ;
ldap_service - > sam_ctx = samdb_connect ( ldap_service ,
ldap_service - > task - > event_ctx ,
ldap_service - > task - > lp_ctx ,
system_session ( ldap_service - > task - > lp_ctx ) ,
NULL ,
0 ) ;
if ( ldap_service - > sam_ctx = = NULL ) {
task_server_terminate ( task , " Cannot open system session LDB " ,
true ) ;
return ;
}
}
2005-01-30 03:54:57 +03:00
2017-04-20 22:24:43 +03:00
NTSTATUS server_service_ldap_init ( TALLOC_CTX * ctx )
2004-09-13 14:36:59 +04:00
{
2018-08-23 00:29:56 +03:00
static const struct service_details details = {
2017-09-14 22:09:23 +03:00
. inhibit_fork_on_accept = false ,
2018-08-23 00:35:52 +03:00
. inhibit_pre_fork = false ,
. task_init = ldapsrv_task_init ,
2019-05-08 03:40:48 +03:00
. post_fork = ldapsrv_post_fork ,
2017-09-14 22:09:23 +03:00
} ;
2018-08-23 00:35:52 +03:00
return register_server_service ( ctx , " ldap " , & details ) ;
2004-09-13 14:36:59 +04:00
}