2011-01-31 16:40:16 +01:00
/*
* Unix SMB / CIFS implementation .
*
* SVCCTL RPC server keys initialization
*
* Copyright ( c ) 2005 Marcin Krzysztof Porwit
* Copyright ( c ) 2005 Gerald ( Jerry ) Carter
* Copyright ( c ) 2011 Andreas Schneider < asn @ samba . org >
*
* 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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2011-02-25 23:20:06 +01:00
# include "system/filesys.h"
2011-01-31 16:40:16 +01:00
# include "services/services.h"
# include "services/svc_winreg_glue.h"
# include "../librpc/gen_ndr/ndr_winreg_c.h"
# include "rpc_client/cli_winreg_int.h"
# include "rpc_client/cli_winreg.h"
2011-02-08 14:17:14 +01:00
# include "rpc_server/svcctl/srv_svcctl_reg.h"
2011-03-24 12:08:15 +01:00
# include "auth.h"
2011-04-09 18:15:12 +02:00
# include "registry/reg_backend_db.h"
2011-01-31 16:40:16 +01:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_REGISTRY
# define TOP_LEVEL_SERVICES_KEY "SYSTEM\\CurrentControlSet\\Services"
struct rcinit_file_information {
char * description ;
} ;
struct service_display_info {
const char * servicename ;
const char * daemon ;
const char * dispname ;
const char * description ;
} ;
static struct service_display_info builtin_svcs [ ] = {
{
" Spooler " ,
" smbd " ,
" Print Spooler " ,
" Internal service for spooling files to print devices "
} ,
{
" NETLOGON " ,
" smbd " ,
" Net Logon " ,
" File service providing access to policy and profile data (not "
" remotely manageable) "
} ,
{
" RemoteRegistry " ,
" smbd " ,
" Remote Registry Service " ,
" Internal service providing remote access to the Samba registry "
} ,
{
" WINS " ,
" nmbd " ,
" Windows Internet Name Service (WINS) " ,
" Internal service providing a NetBIOS point-to-point name server "
" (not remotely manageable) "
} ,
{ NULL , NULL , NULL , NULL }
} ;
static struct service_display_info common_unix_svcs [ ] = {
{ " cups " , NULL , " Common Unix Printing System " , " Provides unified printing support for all operating systems " } ,
{ " postfix " , NULL , " Internet Mail Service " , " Provides support for sending and receiving electonic mail " } ,
{ " sendmail " , NULL , " Internet Mail Service " , " Provides support for sending and receiving electonic mail " } ,
{ " portmap " , NULL , " TCP Port to RPC PortMapper " , NULL } ,
{ " xinetd " , NULL , " Internet Meta-Daemon " , NULL } ,
{ " inet " , NULL , " Internet Meta-Daemon " , NULL } ,
{ " xntpd " , NULL , " Network Time Service " , NULL } ,
{ " ntpd " , NULL , " Network Time Service " , NULL } ,
{ " lpd " , NULL , " BSD Print Spooler " , NULL } ,
{ " nfsserver " , NULL , " Network File Service " , NULL } ,
{ " cron " , NULL , " Scheduling Service " , NULL } ,
{ " at " , NULL , " Scheduling Service " , NULL } ,
{ " nscd " , NULL , " Name Service Cache Daemon " , NULL } ,
{ " slapd " , NULL , " LDAP Directory Service " , NULL } ,
{ " ldap " , NULL , " LDAP DIrectory Service " , NULL } ,
{ " ypbind " , NULL , " NIS Directory Service " , NULL } ,
{ " courier-imap " , NULL , " IMAP4 Mail Service " , NULL } ,
{ " courier-pop3 " , NULL , " POP3 Mail Service " , NULL } ,
{ " named " , NULL , " Domain Name Service " , NULL } ,
{ " bind " , NULL , " Domain Name Service " , NULL } ,
{ " httpd " , NULL , " HTTP Server " , NULL } ,
{ " apache " , NULL , " HTTP Server " , " Provides s highly scalable and flexible web server "
2017-02-18 09:01:50 +13:00
" capable of implementing various protocols including "
2011-01-31 16:40:16 +01:00
" but not limited to HTTP " } ,
{ " autofs " , NULL , " Automounter " , NULL } ,
{ " squid " , NULL , " Web Cache Proxy " , NULL } ,
{ " perfcountd " , NULL , " Performance Monitoring Daemon " , NULL } ,
{ " pgsql " , NULL , " PgSQL Database Server " , " Provides service for SQL database from Postgresql.org " } ,
{ " arpwatch " , NULL , " ARP Tables watcher " , " Provides service for monitoring ARP tables for changes " } ,
{ " dhcpd " , NULL , " DHCP Server " , " Provides service for dynamic host configuration and IP assignment " } ,
{ " nwserv " , NULL , " NetWare Server Emulator " , " Provides service for emulating Novell NetWare 3.12 server " } ,
{ " proftpd " , NULL , " Professional FTP Server " , " Provides high configurable service for FTP connection and "
" file transferring " } ,
{ " ssh2 " , NULL , " SSH Secure Shell " , " Provides service for secure connection for remote administration " } ,
{ " sshd " , NULL , " SSH Secure Shell " , " Provides service for secure connection for remote administration " } ,
{ NULL , NULL , NULL , NULL }
} ;
/********************************************************************
This is where we do the dirty work of filling in things like the
Display name , Description , etc . . .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static char * svcctl_get_common_service_dispname ( TALLOC_CTX * mem_ctx ,
const char * servicename )
{
uint32_t i ;
for ( i = 0 ; common_unix_svcs [ i ] . servicename ; i + + ) {
if ( strequal ( servicename , common_unix_svcs [ i ] . servicename ) ) {
char * dispname ;
dispname = talloc_asprintf ( mem_ctx , " %s (%s) " ,
common_unix_svcs [ i ] . dispname ,
common_unix_svcs [ i ] . servicename ) ;
if ( dispname = = NULL ) {
return NULL ;
}
return dispname ;
}
}
return talloc_strdup ( mem_ctx , servicename ) ;
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static char * svcctl_cleanup_string ( TALLOC_CTX * mem_ctx ,
const char * string )
{
char * clean = NULL ;
char * begin , * end ;
clean = talloc_strdup ( mem_ctx , string ) ;
if ( clean = = NULL ) {
return NULL ;
}
begin = clean ;
/* trim any beginning whilespace */
while ( isspace ( * begin ) ) {
begin + + ;
}
if ( * begin = = ' \0 ' ) {
return NULL ;
}
/* trim any trailing whitespace or carriage returns.
Start at the end and move backwards */
end = begin + strlen ( begin ) - 1 ;
while ( isspace ( * end ) | | * end = = ' \n ' | | * end = = ' \r ' ) {
* end = ' \0 ' ;
end - - ;
}
return begin ;
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static bool read_init_file ( TALLOC_CTX * mem_ctx ,
const char * servicename ,
struct rcinit_file_information * * service_info )
{
struct rcinit_file_information * info = NULL ;
char * filepath = NULL ;
char str [ 1024 ] ;
2016-11-22 01:44:48 +01:00
FILE * f = NULL ;
2011-01-31 16:40:16 +01:00
char * p = NULL ;
info = talloc_zero ( mem_ctx , struct rcinit_file_information ) ;
if ( info = = NULL ) {
return false ;
}
/* attempt the file open */
filepath = talloc_asprintf ( mem_ctx ,
" %s/%s/%s " ,
get_dyn_MODULESDIR ( ) ,
SVCCTL_SCRIPT_DIR ,
servicename ) ;
if ( filepath = = NULL ) {
return false ;
}
2016-11-22 01:44:48 +01:00
f = fopen ( filepath , " r " ) ;
2011-01-31 16:40:16 +01:00
if ( f = = NULL ) {
DEBUG ( 0 , ( " read_init_file: failed to open [%s] \n " , filepath ) ) ;
return false ;
}
2016-11-22 01:44:48 +01:00
while ( ( fgets ( str , sizeof ( str ) - 1 , f ) ) ! = NULL ) {
2011-01-31 16:40:16 +01:00
/* ignore everything that is not a full line
comment starting with a ' # ' */
if ( str [ 0 ] ! = ' # ' ) {
continue ;
}
/* Look for a line like '^#.*Description:' */
p = strstr ( str , " Description: " ) ;
if ( p ! = NULL ) {
char * desc ;
2012-12-17 14:40:17 +01:00
size_t len = strlen ( p ) ;
2011-01-31 16:40:16 +01:00
2012-12-17 14:40:17 +01:00
if ( len < = 12 ) {
2011-01-31 16:40:16 +01:00
break ;
}
2012-12-17 14:40:17 +01:00
desc = svcctl_cleanup_string ( mem_ctx , p + 12 ) ;
2011-01-31 16:40:16 +01:00
if ( desc ! = NULL ) {
info - > description = talloc_strdup ( info , desc ) ;
}
}
}
2016-11-22 01:44:48 +01:00
fclose ( f ) ;
2011-01-31 16:40:16 +01:00
if ( info - > description = = NULL ) {
info - > description = talloc_strdup ( info ,
" External Unix Service " ) ;
if ( info - > description = = NULL ) {
return false ;
}
}
* service_info = info ;
return true ;
}
static bool svcctl_add_service ( TALLOC_CTX * mem_ctx ,
struct dcerpc_binding_handle * h ,
struct policy_handle * hive_hnd ,
const char * key ,
uint32_t access_mask ,
const char * name )
{
enum winreg_CreateAction action = REG_ACTION_NONE ;
struct security_descriptor * sd = NULL ;
struct policy_handle key_hnd ;
struct winreg_String wkey ;
struct winreg_String wkeyclass ;
char * description = NULL ;
char * dname = NULL ;
char * ipath = NULL ;
bool ok = false ;
uint32_t i ;
NTSTATUS status ;
WERROR result = WERR_OK ;
ZERO_STRUCT ( key_hnd ) ;
ZERO_STRUCT ( wkey ) ;
wkey . name = talloc_asprintf ( mem_ctx , " %s \\ %s " , key , name ) ;
if ( wkey . name = = NULL ) {
goto done ;
}
ZERO_STRUCT ( wkeyclass ) ;
wkeyclass . name = " " ;
status = dcerpc_winreg_CreateKey ( h ,
mem_ctx ,
hive_hnd ,
wkey ,
wkeyclass ,
0 ,
access_mask ,
NULL ,
& key_hnd ,
& action ,
& result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create key %s: %s \n " ,
wkey . name , nt_errstr ( status ) ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create key %s: %s \n " ,
wkey . name , win_errstr ( result ) ) ) ;
goto done ;
}
/* These values are hardcoded in all QueryServiceConfig() replies.
I ' m just storing them here for cosmetic purposes */
status = dcerpc_winreg_set_dword ( mem_ctx ,
h ,
& key_hnd ,
" Start " ,
SVCCTL_AUTO_START ,
& result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create value: %s \n " ,
nt_errstr ( status ) ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create value: %s \n " ,
win_errstr ( result ) ) ) ;
goto done ;
}
status = dcerpc_winreg_set_dword ( mem_ctx ,
h ,
& key_hnd ,
" Type " ,
SERVICE_TYPE_WIN32_OWN_PROCESS ,
& result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create value: %s \n " ,
nt_errstr ( status ) ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create value: %s \n " ,
win_errstr ( result ) ) ) ;
goto done ;
}
status = dcerpc_winreg_set_dword ( mem_ctx ,
h ,
& key_hnd ,
" ErrorControl " ,
SVCCTL_SVC_ERROR_NORMAL ,
& result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create value: %s \n " ,
nt_errstr ( status ) ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create value: %s \n " ,
win_errstr ( result ) ) ) ;
goto done ;
}
status = dcerpc_winreg_set_sz ( mem_ctx ,
h ,
& key_hnd ,
" ObjectName " ,
" LocalSystem " ,
& result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create value: %s \n " ,
nt_errstr ( status ) ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create value: %s \n " ,
win_errstr ( result ) ) ) ;
goto done ;
}
/*
* Special considerations for internal services and the DisplayName
* value .
*/
for ( i = 0 ; builtin_svcs [ i ] . servicename ; i + + ) {
if ( strequal ( name , builtin_svcs [ i ] . servicename ) ) {
ipath = talloc_asprintf ( mem_ctx ,
" %s/%s/%s " ,
get_dyn_MODULESDIR ( ) ,
SVCCTL_SCRIPT_DIR ,
builtin_svcs [ i ] . daemon ) ;
description = talloc_strdup ( mem_ctx , builtin_svcs [ i ] . description ) ;
dname = talloc_strdup ( mem_ctx , builtin_svcs [ i ] . dispname ) ;
break ;
}
}
/* Default to an external service if we haven't found a match */
if ( builtin_svcs [ i ] . servicename = = NULL ) {
struct rcinit_file_information * init_info = NULL ;
char * dispname = NULL ;
ipath = talloc_asprintf ( mem_ctx ,
" %s/%s/%s " ,
get_dyn_MODULESDIR ( ) ,
SVCCTL_SCRIPT_DIR ,
name ) ;
/* lookup common unix display names */
dispname = svcctl_get_common_service_dispname ( mem_ctx , name ) ;
dname = talloc_strdup ( mem_ctx , dispname ? dispname : " " ) ;
/* get info from init file itself */
if ( read_init_file ( mem_ctx , name , & init_info ) ) {
description = talloc_strdup ( mem_ctx ,
init_info - > description ) ;
} else {
description = talloc_strdup ( mem_ctx ,
" External Unix Service " ) ;
}
}
if ( ipath = = NULL | | dname = = NULL | | description = = NULL ) {
goto done ;
}
status = dcerpc_winreg_set_sz ( mem_ctx ,
h ,
& key_hnd ,
" DisplayName " ,
dname ,
& result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create value: %s \n " ,
nt_errstr ( status ) ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create value: %s \n " ,
win_errstr ( result ) ) ) ;
goto done ;
}
status = dcerpc_winreg_set_sz ( mem_ctx ,
h ,
& key_hnd ,
" ImagePath " ,
ipath ,
& result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create value: %s \n " ,
nt_errstr ( status ) ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create value: %s \n " ,
win_errstr ( result ) ) ) ;
goto done ;
}
status = dcerpc_winreg_set_sz ( mem_ctx ,
h ,
& key_hnd ,
" Description " ,
description ,
& result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create value: %s \n " ,
nt_errstr ( status ) ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create value: %s \n " ,
win_errstr ( result ) ) ) ;
goto done ;
}
sd = svcctl_gen_service_sd ( mem_ctx ) ;
if ( sd = = NULL ) {
DEBUG ( 0 , ( " add_new_svc_name: Failed to create default "
" sec_desc! \n " ) ) ;
goto done ;
}
if ( is_valid_policy_hnd ( & key_hnd ) ) {
dcerpc_winreg_CloseKey ( h , mem_ctx , & key_hnd , & result ) ;
}
2011-02-08 15:33:51 +01:00
ZERO_STRUCT ( key_hnd ) ;
2011-01-31 16:40:16 +01:00
ZERO_STRUCT ( wkey ) ;
wkey . name = talloc_asprintf ( mem_ctx , " %s \\ %s \\ Security " , key , name ) ;
if ( wkey . name = = NULL ) {
2015-12-03 15:24:15 +01:00
result = WERR_NOT_ENOUGH_MEMORY ;
2011-01-31 16:40:16 +01:00
goto done ;
}
ZERO_STRUCT ( wkeyclass ) ;
wkeyclass . name = " " ;
status = dcerpc_winreg_CreateKey ( h ,
mem_ctx ,
hive_hnd ,
wkey ,
wkeyclass ,
0 ,
access_mask ,
NULL ,
& key_hnd ,
& action ,
& result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-08-29 12:52:40 +02:00
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create key %s: %s \n " ,
2011-01-31 16:40:16 +01:00
wkey . name , nt_errstr ( status ) ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
2011-08-29 12:52:40 +02:00
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create key %s: %s \n " ,
2011-01-31 16:40:16 +01:00
wkey . name , win_errstr ( result ) ) ) ;
goto done ;
}
status = dcerpc_winreg_set_sd ( mem_ctx ,
h ,
& key_hnd ,
" Security " ,
sd ,
& result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create value: %s \n " ,
nt_errstr ( status ) ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg_keys: Could not create value: %s \n " ,
win_errstr ( result ) ) ) ;
goto done ;
}
ok = true ;
done :
if ( is_valid_policy_hnd ( & key_hnd ) ) {
dcerpc_winreg_CloseKey ( h , mem_ctx , & key_hnd , & result ) ;
}
return ok ;
}
bool svcctl_init_winreg ( struct messaging_context * msg_ctx )
{
struct dcerpc_binding_handle * h = NULL ;
uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED ;
struct policy_handle hive_hnd , key_hnd ;
const char * * service_list = lp_svcctl_list ( ) ;
const char * * subkeys = NULL ;
uint32_t num_subkeys = 0 ;
char * key = NULL ;
uint32_t i ;
NTSTATUS status ;
WERROR result = WERR_OK ;
bool ok = false ;
TALLOC_CTX * tmp_ctx ;
tmp_ctx = talloc_stackframe ( ) ;
if ( tmp_ctx = = NULL ) {
return false ;
}
DEBUG ( 3 , ( " Initialise the svcctl registry keys if needed. \n " ) ) ;
2011-02-08 15:33:51 +01:00
ZERO_STRUCT ( hive_hnd ) ;
ZERO_STRUCT ( key_hnd ) ;
2011-01-31 16:40:16 +01:00
key = talloc_strdup ( tmp_ctx , TOP_LEVEL_SERVICES_KEY ) ;
2011-02-08 15:33:51 +01:00
if ( key = = NULL ) {
goto done ;
}
2011-01-31 16:40:16 +01:00
status = dcerpc_winreg_int_hklm_openkey ( tmp_ctx ,
2011-02-21 10:25:52 +01:00
get_session_info_system ( ) ,
2011-01-31 16:40:16 +01:00
msg_ctx ,
& h ,
key ,
false ,
access_mask ,
& hive_hnd ,
& key_hnd ,
& result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg: Could not open %s - %s \n " ,
key , nt_errstr ( status ) ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
DEBUG ( 0 , ( " svcctl_init_winreg: Could not open %s - %s \n " ,
key , win_errstr ( result ) ) ) ;
goto done ;
}
/* get all subkeys */
status = dcerpc_winreg_enum_keys ( tmp_ctx ,
h ,
& key_hnd ,
& num_subkeys ,
& subkeys ,
& result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2023-08-30 13:58:18 +12:00
DEBUG ( 0 , ( " svcctl_init_winreg: Could not enum keys at %s - %s \n " ,
2011-01-31 16:40:16 +01:00
key , nt_errstr ( status ) ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
2023-08-30 13:58:18 +12:00
DEBUG ( 0 , ( " svcctl_init_winreg: Could not enum keys at %s - %s \n " ,
2011-01-31 16:40:16 +01:00
key , win_errstr ( result ) ) ) ;
goto done ;
}
for ( i = 0 ; builtin_svcs [ i ] . servicename ! = NULL ; i + + ) {
uint32_t j ;
bool skip = false ;
for ( j = 0 ; j < num_subkeys ; j + + ) {
if ( strequal ( subkeys [ i ] , builtin_svcs [ i ] . servicename ) ) {
skip = true ;
}
}
if ( skip ) {
continue ;
}
ok = svcctl_add_service ( tmp_ctx ,
h ,
& hive_hnd ,
key ,
access_mask ,
builtin_svcs [ i ] . servicename ) ;
if ( ! ok ) {
goto done ;
}
}
for ( i = 0 ; service_list & & service_list [ i ] ; i + + ) {
uint32_t j ;
bool skip = false ;
for ( j = 0 ; j < num_subkeys ; j + + ) {
if ( strequal ( subkeys [ i ] , service_list [ i ] ) ) {
skip = true ;
}
}
if ( skip ) {
continue ;
}
ok = svcctl_add_service ( tmp_ctx ,
h ,
& hive_hnd ,
key ,
access_mask ,
service_list [ i ] ) ;
if ( is_valid_policy_hnd ( & key_hnd ) ) {
dcerpc_winreg_CloseKey ( h , tmp_ctx , & key_hnd , & result ) ;
}
2011-02-08 15:33:51 +01:00
ZERO_STRUCT ( key_hnd ) ;
2011-01-31 16:40:16 +01:00
if ( ! ok ) {
goto done ;
}
}
done :
if ( is_valid_policy_hnd ( & key_hnd ) ) {
dcerpc_winreg_CloseKey ( h , tmp_ctx , & key_hnd , & result ) ;
}
2012-07-18 05:04:31 +09:30
talloc_free ( tmp_ctx ) ;
2011-01-31 16:40:16 +01:00
return ok ;
}
/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */