2001-05-07 09:03:40 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2001-05-07 09:03:40 +04:00
Winbind daemon - miscellaneous other functions
2002-01-10 14:28:14 +03:00
Copyright ( C ) Tim Potter 2000
Copyright ( C ) Andrew Bartlett 2002
2001-05-07 09:03:40 +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
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
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 .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2003-11-12 04:51:10 +03:00
# include "includes.h"
2001-05-07 09:03:40 +04:00
# include "winbindd.h"
2002-07-15 14:35:28 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_WINBIND
2001-05-07 09:03:40 +04:00
/* Check the machine account password is valid */
2005-06-20 17:42:29 +04:00
void winbindd_check_machine_acct ( struct winbindd_cli_state * state )
2005-06-09 02:10:34 +04:00
{
DEBUG ( 3 , ( " [%5lu]: check machine account \n " ,
( unsigned long ) state - > pid ) ) ;
2005-06-20 17:42:29 +04:00
sendto_domain ( state , find_our_domain ( ) ) ;
2005-06-09 02:10:34 +04:00
}
enum winbindd_result winbindd_dual_check_machine_acct ( struct winbindd_domain * domain ,
struct winbindd_cli_state * state )
2001-05-07 09:03:40 +04:00
{
2001-11-23 03:14:04 +03:00
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
2001-07-25 10:16:27 +04:00
int num_retries = 0 ;
2004-01-05 07:10:28 +03:00
struct winbindd_domain * contact_domain ;
2003-07-22 08:31:20 +04:00
DEBUG ( 3 , ( " [%5lu]: check machine account \n " , ( unsigned long ) state - > pid ) ) ;
2001-05-07 09:03:40 +04:00
/* Get trust account password */
2001-07-25 10:16:27 +04:00
again :
2003-09-05 21:57:45 +04:00
2004-01-08 05:15:46 +03:00
contact_domain = find_our_domain ( ) ;
2004-01-05 07:10:28 +03:00
2001-11-23 03:14:04 +03:00
/* This call does a cli_nt_setup_creds() which implicitly checks
the trust account password . */
2005-06-09 02:10:34 +04:00
invalidate_cm_connection ( & contact_domain - > conn ) ;
{
2005-09-30 21:13:37 +04:00
struct rpc_pipe_client * netlogon_pipe ;
result = cm_connect_netlogon ( contact_domain , & netlogon_pipe ) ;
2005-06-09 02:10:34 +04:00
}
2001-05-07 09:03:40 +04:00
2001-11-23 03:14:04 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 3 , ( " could not open handle to NETLOGON pipe \n " ) ) ;
goto done ;
}
2001-05-07 09:03:40 +04:00
2001-07-25 10:16:27 +04:00
/* There is a race condition between fetching the trust account
2002-03-19 09:36:37 +03:00
password and the periodic machine password change . So it ' s
possible that the trust account password has been changed on us .
We are returned NT_STATUS_ACCESS_DENIED if this happens . */
2001-07-25 10:16:27 +04:00
# define MAX_RETRIES 8
if ( ( num_retries < MAX_RETRIES ) & &
2001-11-23 03:14:04 +03:00
NT_STATUS_V ( result ) = = NT_STATUS_V ( NT_STATUS_ACCESS_DENIED ) ) {
2001-07-25 10:16:27 +04:00
num_retries + + ;
goto again ;
}
2001-05-07 09:03:40 +04:00
/* Pass back result code - zero for success, other values for
specific failures . */
2001-11-23 03:14:04 +03:00
DEBUG ( 3 , ( " secret is %s \n " , NT_STATUS_IS_OK ( result ) ?
" good " : " bad " ) ) ;
2001-05-07 09:03:40 +04:00
done :
2002-07-15 14:35:28 +04:00
state - > response . data . auth . nt_status = NT_STATUS_V ( result ) ;
fstrcpy ( state - > response . data . auth . nt_status_string , nt_errstr ( result ) ) ;
fstrcpy ( state - > response . data . auth . error_string , nt_errstr ( result ) ) ;
state - > response . data . auth . pam_error = nt_status_to_pam ( result ) ;
DEBUG ( NT_STATUS_IS_OK ( result ) ? 5 : 2 , ( " Checking the trust account password returned %s \n " ,
state - > response . data . auth . nt_status_string ) ) ;
2001-11-23 03:14:04 +03:00
2002-07-15 14:35:28 +04:00
return NT_STATUS_IS_OK ( result ) ? WINBINDD_OK : WINBINDD_ERROR ;
2001-05-07 09:03:40 +04:00
}
2005-06-20 17:42:29 +04:00
void winbindd_list_trusted_domains ( struct winbindd_cli_state * state )
2001-05-07 09:03:40 +04:00
{
2005-06-09 02:10:34 +04:00
DEBUG ( 3 , ( " [%5lu]: list trusted domains \n " ,
( unsigned long ) state - > pid ) ) ;
2005-06-20 17:42:29 +04:00
sendto_domain ( state , find_our_domain ( ) ) ;
2005-06-09 02:10:34 +04:00
}
2001-05-07 09:03:40 +04:00
2005-06-09 02:10:34 +04:00
enum winbindd_result winbindd_dual_list_trusted_domains ( struct winbindd_domain * domain ,
struct winbindd_cli_state * state )
{
uint32 i , num_domains ;
char * * names , * * alt_names ;
DOM_SID * sids ;
int extra_data_len = 0 ;
char * extra_data ;
NTSTATUS result ;
2001-05-07 09:03:40 +04:00
2005-06-09 02:10:34 +04:00
DEBUG ( 3 , ( " [%5lu]: list trusted domains \n " ,
( unsigned long ) state - > pid ) ) ;
2001-11-15 06:29:00 +03:00
2005-06-09 02:10:34 +04:00
result = domain - > methods - > trusted_domains ( domain , state - > mem_ctx ,
& num_domains , & names ,
& alt_names , & sids ) ;
extra_data = talloc_strdup ( state - > mem_ctx , " " ) ;
if ( num_domains > 0 )
extra_data = talloc_asprintf ( state - > mem_ctx , " %s \\ %s \\ %s " ,
2005-10-03 21:33:43 +04:00
names [ 0 ] ,
alt_names [ 0 ] ? alt_names [ 0 ] : names [ 0 ] ,
2005-06-09 02:10:34 +04:00
sid_string_static ( & sids [ 0 ] ) ) ;
for ( i = 1 ; i < num_domains ; i + + )
extra_data = talloc_asprintf ( state - > mem_ctx , " %s \n %s \\ %s \\ %s " ,
extra_data ,
names [ i ] , alt_names [ i ] ,
sid_string_static ( & sids [ i ] ) ) ;
/* This is a bit excessive, but the extra data sooner or later will be
talloc ' ed */
extra_data_len = strlen ( extra_data ) ;
if ( extra_data_len > 0 ) {
state - > response . extra_data = SMB_STRDUP ( extra_data ) ;
state - > response . length + = extra_data_len + 1 ;
2003-01-15 20:39:47 +03:00
}
2002-01-11 08:33:45 +03:00
2005-06-09 02:10:34 +04:00
return WINBINDD_OK ;
}
2005-06-20 17:42:29 +04:00
void winbindd_getdcname ( struct winbindd_cli_state * state )
2005-06-09 02:10:34 +04:00
{
state - > request . domain_name
[ sizeof ( state - > request . domain_name ) - 1 ] = ' \0 ' ;
2001-05-07 09:03:40 +04:00
2005-06-09 02:10:34 +04:00
DEBUG ( 3 , ( " [%5lu]: Get DC name for %s \n " , ( unsigned long ) state - > pid ,
state - > request . domain_name ) ) ;
2001-05-07 09:03:40 +04:00
2005-06-20 17:42:29 +04:00
sendto_domain ( state , find_our_domain ( ) ) ;
2005-06-09 02:10:34 +04:00
}
2001-05-07 09:03:40 +04:00
2005-06-09 02:10:34 +04:00
enum winbindd_result winbindd_dual_getdcname ( struct winbindd_domain * domain ,
struct winbindd_cli_state * state )
{
fstring dcname_slash ;
char * p ;
2005-09-30 21:13:37 +04:00
struct rpc_pipe_client * netlogon_pipe ;
2005-06-09 02:10:34 +04:00
NTSTATUS result ;
2001-05-07 09:03:40 +04:00
2005-06-09 02:10:34 +04:00
state - > request . domain_name
[ sizeof ( state - > request . domain_name ) - 1 ] = ' \0 ' ;
2001-05-07 09:03:40 +04:00
2005-06-09 02:10:34 +04:00
DEBUG ( 3 , ( " [%5lu]: Get DC name for %s \n " , ( unsigned long ) state - > pid ,
state - > request . domain_name ) ) ;
2001-05-07 09:03:40 +04:00
2005-09-30 21:13:37 +04:00
result = cm_connect_netlogon ( domain , & netlogon_pipe ) ;
2001-05-07 09:03:40 +04:00
2005-06-09 02:10:34 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 1 , ( " Can't contact our the NETLOGON pipe \n " ) ) ;
return WINBINDD_ERROR ;
2001-05-07 09:03:40 +04:00
}
2005-09-30 21:13:37 +04:00
result = rpccli_netlogon_getdcname ( netlogon_pipe , state - > mem_ctx , domain - > dcname ,
2005-06-09 02:10:34 +04:00
state - > request . domain_name ,
dcname_slash ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 5 , ( " Error requesting DCname: %s \n " , nt_errstr ( result ) ) ) ;
return WINBINDD_ERROR ;
2001-05-07 09:03:40 +04:00
}
2005-06-09 02:10:34 +04:00
p = dcname_slash ;
2005-09-30 21:13:37 +04:00
if ( * p = = ' \\ ' ) {
p + = 1 ;
}
if ( * p = = ' \\ ' ) {
p + = 1 ;
}
2005-06-09 02:10:34 +04:00
fstrcpy ( state - > response . data . dc_name , p ) ;
2001-05-07 09:03:40 +04:00
return WINBINDD_OK ;
}
2002-01-10 13:23:54 +03:00
2005-06-09 02:10:34 +04:00
struct sequence_state {
TALLOC_CTX * mem_ctx ;
struct winbindd_cli_state * cli_state ;
struct winbindd_domain * domain ;
struct winbindd_request * request ;
struct winbindd_response * response ;
char * extra_data ;
} ;
2005-06-25 00:25:18 +04:00
static void sequence_recv ( void * private_data , BOOL success ) ;
2002-01-31 14:49:29 +03:00
2005-06-20 17:42:29 +04:00
void winbindd_show_sequence ( struct winbindd_cli_state * state )
2002-01-31 14:49:29 +03:00
{
2005-06-09 02:10:34 +04:00
struct sequence_state * seq ;
/* Ensure null termination */
state - > request . domain_name [ sizeof ( state - > request . domain_name ) - 1 ] = ' \0 ' ;
if ( strlen ( state - > request . domain_name ) > 0 ) {
struct winbindd_domain * domain ;
domain = find_domain_from_name_noinit (
state - > request . domain_name ) ;
2005-06-20 17:42:29 +04:00
if ( domain = = NULL ) {
request_error ( state ) ;
return ;
}
sendto_domain ( state , domain ) ;
return ;
2005-06-09 02:10:34 +04:00
}
/* Ask all domains in sequence, collect the results in sequence_recv */
2002-01-31 14:49:29 +03:00
2005-06-09 02:10:34 +04:00
seq = TALLOC_P ( state - > mem_ctx , struct sequence_state ) ;
if ( seq = = NULL ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
2005-06-20 17:42:29 +04:00
request_error ( state ) ;
return ;
2005-06-09 02:10:34 +04:00
}
seq - > mem_ctx = state - > mem_ctx ;
seq - > cli_state = state ;
seq - > domain = domain_list ( ) ;
if ( seq - > domain = = NULL ) {
DEBUG ( 0 , ( " domain list empty \n " ) ) ;
2005-06-20 17:42:29 +04:00
request_error ( state ) ;
return ;
2005-06-09 02:10:34 +04:00
}
seq - > request = TALLOC_ZERO_P ( state - > mem_ctx ,
struct winbindd_request ) ;
seq - > response = TALLOC_ZERO_P ( state - > mem_ctx ,
struct winbindd_response ) ;
seq - > extra_data = talloc_strdup ( state - > mem_ctx , " " ) ;
if ( ( seq - > request = = NULL ) | | ( seq - > response = = NULL ) | |
( seq - > extra_data = = NULL ) ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
2005-06-20 17:42:29 +04:00
request_error ( state ) ;
return ;
2005-06-09 02:10:34 +04:00
}
seq - > request - > length = sizeof ( * seq - > request ) ;
seq - > request - > cmd = WINBINDD_SHOW_SEQUENCE ;
fstrcpy ( seq - > request - > domain_name , seq - > domain - > name ) ;
async_domain_request ( state - > mem_ctx , seq - > domain ,
seq - > request , seq - > response ,
sequence_recv , seq ) ;
}
2005-06-25 00:25:18 +04:00
static void sequence_recv ( void * private_data , BOOL success )
2005-06-09 02:10:34 +04:00
{
2005-06-25 00:25:18 +04:00
struct sequence_state * state = private_data ;
2005-06-09 02:10:34 +04:00
uint32 seq = DOM_SEQUENCE_NONE ;
if ( ( success ) & & ( state - > response - > result = = WINBINDD_OK ) )
seq = state - > response - > data . domain_info . sequence_number ;
if ( seq = = DOM_SEQUENCE_NONE ) {
state - > extra_data = talloc_asprintf ( state - > mem_ctx ,
" %s%s : DISCONNECTED \n " ,
state - > extra_data ,
state - > domain - > name ) ;
} else {
state - > extra_data = talloc_asprintf ( state - > mem_ctx ,
" %s%s : %d \n " ,
state - > extra_data ,
state - > domain - > name , seq ) ;
}
state - > domain - > sequence_number = seq ;
state - > domain = state - > domain - > next ;
if ( state - > domain = = NULL ) {
struct winbindd_cli_state * cli_state = state - > cli_state ;
cli_state - > response . length =
sizeof ( cli_state - > response ) +
strlen ( state - > extra_data ) + 1 ;
cli_state - > response . extra_data =
SMB_STRDUP ( state - > extra_data ) ;
2005-06-20 17:42:29 +04:00
request_ok ( cli_state ) ;
2005-06-09 02:10:34 +04:00
return ;
}
/* Ask the next domain */
fstrcpy ( state - > request - > domain_name , state - > domain - > name ) ;
async_domain_request ( state - > mem_ctx , state - > domain ,
state - > request , state - > response ,
sequence_recv , state ) ;
}
/* This is the child-only version of --sequence. It only allows for a single
* domain ( ie " our " one ) to be displayed . */
enum winbindd_result winbindd_dual_show_sequence ( struct winbindd_domain * domain ,
struct winbindd_cli_state * state )
{
2003-07-22 08:31:20 +04:00
DEBUG ( 3 , ( " [%5lu]: show sequence \n " , ( unsigned long ) state - > pid ) ) ;
2002-01-31 14:49:29 +03:00
2003-08-11 02:01:11 +04:00
/* Ensure null termination */
2005-06-09 02:10:34 +04:00
state - > request . domain_name [ sizeof ( state - > request . domain_name ) - 1 ] = ' \0 ' ;
2002-01-31 14:49:29 +03:00
2005-06-09 02:10:34 +04:00
domain - > methods - > sequence_number ( domain , & domain - > sequence_number ) ;
state - > response . data . domain_info . sequence_number =
domain - > sequence_number ;
2002-01-31 14:49:29 +03:00
return WINBINDD_OK ;
}
2005-06-09 02:10:34 +04:00
struct domain_info_state {
struct winbindd_domain * domain ;
struct winbindd_cli_state * cli_state ;
} ;
2005-06-25 00:25:18 +04:00
static void domain_info_init_recv ( void * private_data , BOOL success ) ;
2005-06-09 02:10:34 +04:00
2005-06-20 17:42:29 +04:00
void winbindd_domain_info ( struct winbindd_cli_state * state )
2004-01-04 14:51:31 +03:00
{
struct winbindd_domain * domain ;
DEBUG ( 3 , ( " [%5lu]: domain_info [%s] \n " , ( unsigned long ) state - > pid ,
state - > request . domain_name ) ) ;
2005-06-09 02:10:34 +04:00
domain = find_domain_from_name_noinit ( state - > request . domain_name ) ;
2004-01-04 14:51:31 +03:00
if ( domain = = NULL ) {
DEBUG ( 3 , ( " Did not find domain [%s] \n " ,
state - > request . domain_name ) ) ;
2005-06-20 17:42:29 +04:00
request_error ( state ) ;
return ;
2004-01-04 14:51:31 +03:00
}
2005-06-09 02:10:34 +04:00
if ( ! domain - > initialized ) {
struct domain_info_state * istate ;
istate = TALLOC_P ( state - > mem_ctx , struct domain_info_state ) ;
if ( istate = = NULL ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
2005-06-20 17:42:29 +04:00
request_error ( state ) ;
return ;
2005-06-09 02:10:34 +04:00
}
istate - > cli_state = state ;
istate - > domain = domain ;
init_child_connection ( domain , domain_info_init_recv , istate ) ;
2005-06-20 17:42:29 +04:00
return ;
2005-06-09 02:10:34 +04:00
}
fstrcpy ( state - > response . data . domain_info . name ,
domain - > name ) ;
fstrcpy ( state - > response . data . domain_info . alt_name ,
domain - > alt_name ) ;
2004-01-04 14:51:31 +03:00
fstrcpy ( state - > response . data . domain_info . sid ,
sid_string_static ( & domain - > sid ) ) ;
2005-06-09 02:10:34 +04:00
state - > response . data . domain_info . native_mode =
domain - > native_mode ;
state - > response . data . domain_info . active_directory =
domain - > active_directory ;
state - > response . data . domain_info . primary =
domain - > primary ;
2004-01-04 14:51:31 +03:00
state - > response . data . domain_info . sequence_number =
domain - > sequence_number ;
2005-06-20 17:42:29 +04:00
request_ok ( state ) ;
2004-01-04 14:51:31 +03:00
}
2005-06-25 00:25:18 +04:00
static void domain_info_init_recv ( void * private_data , BOOL success )
2005-06-09 02:10:34 +04:00
{
2005-06-25 00:25:18 +04:00
struct domain_info_state * istate = private_data ;
2005-06-09 02:10:34 +04:00
struct winbindd_cli_state * state = istate - > cli_state ;
struct winbindd_domain * domain = istate - > domain ;
DEBUG ( 10 , ( " Got back from child init: %d \n " , success ) ) ;
if ( ( ! success ) | | ( ! domain - > initialized ) ) {
DEBUG ( 5 , ( " Could not init child for domain %s \n " ,
domain - > name ) ) ;
2005-06-20 17:42:29 +04:00
request_error ( state ) ;
2005-06-09 02:10:34 +04:00
return ;
}
fstrcpy ( state - > response . data . domain_info . name ,
domain - > name ) ;
fstrcpy ( state - > response . data . domain_info . alt_name ,
domain - > alt_name ) ;
fstrcpy ( state - > response . data . domain_info . sid ,
sid_string_static ( & domain - > sid ) ) ;
state - > response . data . domain_info . native_mode =
domain - > native_mode ;
state - > response . data . domain_info . active_directory =
domain - > active_directory ;
state - > response . data . domain_info . primary =
domain - > primary ;
state - > response . data . domain_info . sequence_number =
domain - > sequence_number ;
2005-06-20 17:42:29 +04:00
request_ok ( state ) ;
2005-06-09 02:10:34 +04:00
}
2005-06-20 17:42:29 +04:00
void winbindd_ping ( struct winbindd_cli_state * state )
2002-01-10 13:23:54 +03:00
{
2003-07-22 08:31:20 +04:00
DEBUG ( 3 , ( " [%5lu]: ping \n " , ( unsigned long ) state - > pid ) ) ;
2005-06-20 17:42:29 +04:00
request_ok ( state ) ;
2002-01-10 13:23:54 +03:00
}
2002-01-10 14:28:14 +03:00
/* List various tidbits of information */
2005-06-20 17:42:29 +04:00
void winbindd_info ( struct winbindd_cli_state * state )
2002-01-10 14:28:14 +03:00
{
2003-07-22 08:31:20 +04:00
DEBUG ( 3 , ( " [%5lu]: request misc info \n " , ( unsigned long ) state - > pid ) ) ;
2002-01-10 14:28:14 +03:00
state - > response . data . info . winbind_separator = * lp_winbind_separator ( ) ;
2003-08-20 21:13:38 +04:00
fstrcpy ( state - > response . data . info . samba_version , SAMBA_VERSION_STRING ) ;
2005-06-20 17:42:29 +04:00
request_ok ( state ) ;
2002-01-10 14:28:14 +03:00
}
2002-01-26 12:52:55 +03:00
/* Tell the client the current interface version */
2002-01-10 14:28:14 +03:00
2005-06-20 17:42:29 +04:00
void winbindd_interface_version ( struct winbindd_cli_state * state )
2002-01-10 14:28:14 +03:00
{
2005-06-20 17:42:29 +04:00
DEBUG ( 3 , ( " [%5lu]: request interface version \n " ,
( unsigned long ) state - > pid ) ) ;
2002-01-10 14:28:14 +03:00
state - > response . data . interface_version = WINBIND_INTERFACE_VERSION ;
2005-06-20 17:42:29 +04:00
request_ok ( state ) ;
2002-01-10 14:28:14 +03:00
}
2002-01-26 12:52:55 +03:00
/* What domain are we a member of? */
2005-06-20 17:42:29 +04:00
void winbindd_domain_name ( struct winbindd_cli_state * state )
2002-01-26 12:52:55 +03:00
{
2003-07-22 08:31:20 +04:00
DEBUG ( 3 , ( " [%5lu]: request domain name \n " , ( unsigned long ) state - > pid ) ) ;
2002-01-26 12:52:55 +03:00
fstrcpy ( state - > response . data . domain_name , lp_workgroup ( ) ) ;
2005-06-20 17:42:29 +04:00
request_ok ( state ) ;
2002-01-26 12:52:55 +03:00
}
2003-01-28 15:07:02 +03:00
/* What's my name again? */
2005-06-20 17:42:29 +04:00
void winbindd_netbios_name ( struct winbindd_cli_state * state )
2003-01-28 15:07:02 +03:00
{
2005-06-20 17:42:29 +04:00
DEBUG ( 3 , ( " [%5lu]: request netbios name \n " ,
( unsigned long ) state - > pid ) ) ;
2003-01-28 15:07:02 +03:00
fstrcpy ( state - > response . data . netbios_name , global_myname ( ) ) ;
2005-06-20 17:42:29 +04:00
request_ok ( state ) ;
2003-01-28 15:07:02 +03:00
}
2003-03-24 12:54:13 +03:00
2003-04-21 18:09:03 +04:00
/* Where can I find the privilaged pipe? */
2003-03-24 12:54:13 +03:00
2005-06-20 17:42:29 +04:00
void winbindd_priv_pipe_dir ( struct winbindd_cli_state * state )
2003-03-24 12:54:13 +03:00
{
2005-06-20 17:42:29 +04:00
DEBUG ( 3 , ( " [%5lu]: request location of privileged pipe \n " ,
( unsigned long ) state - > pid ) ) ;
2003-03-24 12:54:13 +03:00
2004-12-07 21:25:53 +03:00
state - > response . extra_data = SMB_STRDUP ( get_winbind_priv_pipe_dir ( ) ) ;
2005-06-20 17:42:29 +04:00
if ( ! state - > response . extra_data ) {
DEBUG ( 0 , ( " malloc failed \n " ) ) ;
request_error ( state ) ;
return ;
}
2003-03-24 12:54:13 +03:00
/* must add one to length to copy the 0 for string termination */
2005-06-20 17:42:29 +04:00
state - > response . length + =
strlen ( ( char * ) state - > response . extra_data ) + 1 ;
2003-03-24 12:54:13 +03:00
2005-06-20 17:42:29 +04:00
request_ok ( state ) ;
2003-03-24 12:54:13 +03:00
}