From 0555c5b4c069540fecf72646fe1a80796139f1c6 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Tue, 13 Sep 2005 17:03:18 +0000 Subject: [PATCH] r10206: * QueryServiceConfig2() now works, but only for info level SERVICE_CONFIG_DESCRIPTION. * MMC service control plugin is now able to bring up the properties of a service (with a few error messages about unsupported rpc calls). * rename 'enable svcctl' to 'svcctl list' for better consistency with the 'eventlog list' smb.conf parameter. --- source/include/rpc_svcctl.h | 3 +- source/param/loadparm.c | 4 +- source/rpc_parse/parse_svcctl.c | 85 ++++------- source/rpc_server/srv_svcctl_nt.c | 30 +++- source/services/services_db.c | 305 ++++++++------------------------------ 5 files changed, 118 insertions(+), 309 deletions(-) diff --git a/source/include/rpc_svcctl.h b/source/include/rpc_svcctl.h index c92fcc5e354..8f445e5c52a 100644 --- a/source/include/rpc_svcctl.h +++ b/source/include/rpc_svcctl.h @@ -155,7 +155,8 @@ typedef struct { } SERVICE_CONFIG; typedef struct { - UNISTR2 *description; + uint32 unknown; + UNISTR description; } SERVICE_DESCRIPTION; typedef struct { diff --git a/source/param/loadparm.c b/source/param/loadparm.c index 3769d378a69..212843e808c 100644 --- a/source/param/loadparm.c +++ b/source/param/loadparm.c @@ -969,7 +969,7 @@ static struct parm_struct parm_table[] = { {"client use spnego", P_BOOL, P_GLOBAL, &Globals.bClientUseSpnego, NULL, NULL, FLAG_ADVANCED}, {"enable asu support", P_BOOL, P_GLOBAL, &Globals.bASUSupport, NULL, NULL, FLAG_ADVANCED}, - {"enable svcctl", P_LIST, P_GLOBAL, &Globals.szServicesList, NULL, NULL, FLAG_ADVANCED}, + {"svcctl list", P_LIST, P_GLOBAL, &Globals.szServicesList, NULL, NULL, FLAG_ADVANCED}, {N_("Tuning Options"), P_SEP, P_SEPARATOR}, @@ -1914,7 +1914,7 @@ FN_LOCAL_STRING(lp_username, szUsername) FN_LOCAL_LIST(lp_invalid_users, szInvalidUsers) FN_LOCAL_LIST(lp_valid_users, szValidUsers) FN_LOCAL_LIST(lp_admin_users, szAdminUsers) -FN_GLOBAL_LIST(lp_enable_svcctl, &Globals.szServicesList) +FN_GLOBAL_LIST(lp_svcctl_list, &Globals.szServicesList) FN_LOCAL_STRING(lp_cups_options, szCupsOptions) FN_GLOBAL_STRING(lp_cups_server, &Globals.szCupsServer) FN_LOCAL_STRING(lp_printcommand, szPrintcommand) diff --git a/source/rpc_parse/parse_svcctl.c b/source/rpc_parse/parse_svcctl.c index 10735445057..81dff3b3d63 100644 --- a/source/rpc_parse/parse_svcctl.c +++ b/source/rpc_parse/parse_svcctl.c @@ -100,21 +100,6 @@ static BOOL svcctl_io_service_config( const char *desc, SERVICE_CONFIG *config, return True; } -/******************************************************************* -********************************************************************/ - -BOOL svcctl_io_service_description( const char *desc, UNISTR2 *svcdesc, prs_struct *ps, int depth ) -{ - - prs_debug(ps, depth, desc, "svcctl_io_service_description"); - depth++; - - if (!prs_io_unistr2("", ps, depth, svcdesc)) - return False; - - return True; -} - /******************************************************************* ********************************************************************/ @@ -767,34 +752,42 @@ BOOL svcctl_io_q_query_service_config2(const char *desc, SVCCTL_Q_QUERY_SERVICE_ /******************************************************************* - Creates a service description response buffer. - The format seems to be DWORD:length of buffer - DWORD:offset (fixed as four) - UNISTR: unicode description in the rest of the buffer ********************************************************************/ -void init_service_description_buffer(RPC_DATA_BLOB *str, const char *service_desc, int blob_length) +void init_service_description_buffer(SERVICE_DESCRIPTION *desc, const char *service_desc ) +{ + desc->unknown = 0x04; /* always 0x0000 0004 (no idea what this is) */ + init_unistr( &desc->description, service_desc ); +} + +/******************************************************************* +********************************************************************/ + +BOOL svcctl_io_service_description( const char *desc, SERVICE_DESCRIPTION *description, RPC_BUFFER *buffer, int depth ) { - uint32 offset; - uint8 *bp; + prs_struct *ps = &buffer->prs; - ZERO_STRUCTP(str); + prs_debug(ps, depth, desc, "svcctl_io_service_description"); + depth++; + + if ( !prs_uint32("unknown", ps, depth, &description->unknown) ) + return False; + if ( !prs_unistr("description", ps, depth, &description->description) ) + return False; - offset = 4; + return True; +} - /* set up string lengths. */ +/******************************************************************* +********************************************************************/ - str->buf_len = create_rpc_blob(str, blob_length); - DEBUG(10, ("init_service_description buffer: Allocated a blob of [%d] \n",str->buf_len)); +uint32 svcctl_sizeof_service_description( SERVICE_DESCRIPTION *desc ) +{ + if ( !desc ) + return 0; - if ( str && str->buffer && str->buf_len) { - memset(str->buffer,0,str->buf_len); - memcpy(str->buffer, &offset, sizeof(uint32)); - bp = &str->buffer[4]; - if (service_desc) { - rpcstr_push(bp, service_desc,str->buf_len-4,0); - } - } + /* make sure to include the terminating NULL */ + return ( sizeof(uint32) + (2*(str_len_uni(&desc->description)+1)) ); } /******************************************************************* @@ -811,27 +804,11 @@ BOOL svcctl_io_r_query_service_config2(const char *desc, SVCCTL_R_QUERY_SERVICE_ if ( !prs_align(ps) ) return False; -#if 0 - if(!prs_uint32("returned", ps, depth, &r_u->returned)) + if (!prs_rpcbuffer("", ps, depth, &r_u->buffer)) + return False; + if(!prs_align(ps)) return False; - if (r_u->returned > 4) { - if (!prs_uint32("offset", ps, depth, &r_u->offset)) - return False; - - if ( !prs_pointer( desc, ps, depth, (void**)&r_u->description, sizeof(UNISTR2), (PRS_POINTER_CAST)prs_io_unistr2 ) ) - return False; - - if(!prs_align(ps)) - return False; - } else { - /* offset does double duty here */ - r_u->offset = 0; - if (!prs_uint32("offset", ps, depth, &r_u->offset)) - return False; - } - -#endif if (!prs_uint32("needed", ps, depth, &r_u->needed)) return False; diff --git a/source/rpc_server/srv_svcctl_nt.c b/source/rpc_server/srv_svcctl_nt.c index daaa19aa98b..c9414813a4c 100644 --- a/source/rpc_server/srv_svcctl_nt.c +++ b/source/rpc_server/srv_svcctl_nt.c @@ -45,7 +45,7 @@ struct service_control_op *svcctl_ops; BOOL init_service_op_table( void ) { - const char **service_list = lp_enable_svcctl(); + const char **service_list = lp_svcctl_list(); int num_services = 3 + str_list_count( service_list ); int i; @@ -630,6 +630,7 @@ WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CON WERROR _svcctl_query_service_config2( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG2 *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG2 *r_u ) { SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle ); + uint32 buffer_size; /* perform access checks */ @@ -642,16 +643,33 @@ WERROR _svcctl_query_service_config2( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CO /* we have to set the outgoing buffer size to the same as the incoming buffer size (even in the case of failure */ - r_u->needed = q_u->buffer_size; + rpcbuf_init( &r_u->buffer, q_u->buffer_size, p->mem_ctx ); + r_u->needed = q_u->buffer_size; switch ( q_u->level ) { - - case SERVICE_CONFIG_DESCRIPTION: + case SERVICE_CONFIG_DESCRIPTION: + { + SERVICE_DESCRIPTION desc_buf; + const char *description; + + description = svcctl_lookup_description( info->name, p->pipe_user.nt_user_token ); + + ZERO_STRUCTP( &desc_buf ); + init_service_description_buffer( &desc_buf, description ); + svcctl_io_service_description( "", &desc_buf, &r_u->buffer, 0 ); + buffer_size = svcctl_sizeof_service_description( &desc_buf ); break; + } + break; - default: - return WERR_UNKNOWN_LEVEL; + default: + return WERR_UNKNOWN_LEVEL; } + + r_u->needed = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size; + + if (buffer_size > q_u->buffer_size ) + return WERR_INSUFFICIENT_BUFFER; return WERR_OK; } diff --git a/source/services/services_db.c b/source/services/services_db.c index 45695ad0d5c..f5d404cc55e 100644 --- a/source/services/services_db.c +++ b/source/services/services_db.c @@ -1,8 +1,10 @@ /* * Unix SMB/CIFS implementation. * Service Control API Implementation - * Copyright (C) Gerald Carter 2005. + * * Copyright (C) Marcin Krzysztof Porwit 2005. + * Largely Rewritten by: + * Copyright (C) Gerald (Jerry) Carter 2005. * * 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 @@ -21,240 +23,6 @@ #include "includes.h" -#if 0 -/******************************************************************** - Gather information on the "external services". These are services - listed in the smb.conf file, and found to exist through checks in - this code. Note that added will be incremented on the basis of the - number of services added. svc_ptr should have enough memory allocated - to accommodate all of the services that exist. - - Typically num_external_services is used to "size" the amount of - memory allocated, but does little/no work. - - enum_external_services() actually examines each of the specified - external services, populates the memory structures, and returns. - - ** note that 'added' may end up with less than the number of services - found in _num_external_services, such as the case when a service is - called out, but the actual service doesn't exist or the file can't be - read for the service information. -********************************************************************/ - -WERROR enum_external_services(TALLOC_CTX *tcx,ENUM_SERVICES_STATUS **svc_ptr, int existing_services,int *added) -{ - /* *svc_ptr must have pre-allocated memory */ - int num_services = 0; - int i = 0; - ENUM_SERVICES_STATUS *services=NULL; - char **svc_list,**svcname; - pstring command, keystring, external_services_string; - int ret; - int fd = -1; - Service_info *si; - TDB_DATA key_data; - - *added = num_services; - - if (!service_tdb) { - DEBUG(8,("enum_external_services: service database is not open!!!\n")); - } else { - pstrcpy(keystring,"EXTERNAL_SERVICES"); - key_data = tdb_fetch_bystring(service_tdb, keystring); - if ((key_data.dptr != NULL) && (key_data.dsize != 0)) { - strncpy(external_services_string,key_data.dptr,key_data.dsize); - external_services_string[key_data.dsize] = 0; - DEBUG(8,("enum_external_services: services list is %s, size is %d\n", - external_services_string,(int)key_data.dsize)); - } - } - svc_list = str_list_make(external_services_string,NULL); - - num_services = str_list_count( (const char **)svc_list); - - if (0 == num_services) { - DEBUG(8,("enum_external_services: there are no external services\n")); - *added = num_services; - return WERR_OK; - } - DEBUG(8,("enum_external_services: there are [%d] external services\n",num_services)); - si=TALLOC_ARRAY( tcx, Service_info, 1 ); - if (si == NULL) { - DEBUG(8,("enum_external_services: Failed to alloc si\n")); - return WERR_NOMEM; - } - - /* *svc_ptr has the pointer to the array if there is one already. NULL if not. */ - if ((existing_services>0) && svc_ptr && *svc_ptr) { /* reallocate vs. allocate */ - DEBUG(8,("enum_external_services: REALLOCing %x to %d services\n", *svc_ptr, existing_services+num_services)); - - services=TALLOC_REALLOC_ARRAY(tcx,*svc_ptr,ENUM_SERVICES_STATUS,existing_services+num_services); - DEBUG(8,("enum_external_services: REALLOCed to %x services\n", services)); - - if (!services) return WERR_NOMEM; - *svc_ptr = services; - } else { - if ( !(services = TALLOC_ARRAY( tcx, ENUM_SERVICES_STATUS, num_services )) ) - return WERR_NOMEM; - } - - if (!svc_ptr || !(*svc_ptr)) - return WERR_NOMEM; - services = *svc_ptr; - if (existing_services > 0) { - i+=existing_services; - } - - svcname = svc_list; - DEBUG(8,("enum_external_services: enumerating %d external services starting at index %d\n", num_services,existing_services)); - - while (*svcname) { - DEBUG(10,("enum_external_services: Reading information on service %s, index %d\n",*svcname,i)); - /* get_LSB_data(*svcname,si); */ - if (!get_service_info(service_tdb,*svcname, si)) { - DEBUG(1,("enum_external_services: CAN'T FIND INFO FOR SERVICE %s in the services DB\n",*svcname)); - } - - if ((si->filename == NULL) || (*si->filename == 0)) { - init_unistr(&services[i].servicename, *svcname ); - } else { - init_unistr( &services[i].servicename, si->filename ); - /* init_unistr( &services[i].servicename, si->servicename ); */ - } - - if ((si->provides == NULL) || (*si->provides == 0)) { - init_unistr(&services[i].displayname, *svcname ); - } else { - init_unistr( &services[i].displayname, si->provides ); - } - - /* TODO - we could keep the following info in the DB, too... */ - - DEBUG(8,("enum_external_services: Service name [%s] displayname [%s]\n", - si->filename, si->provides)); - services[i].status.type = SVCCTL_WIN32_OWN_PROC; - services[i].status.win32_exit_code = 0x0; - services[i].status.service_exit_code = 0x0; - services[i].status.check_point = 0x0; - services[i].status.wait_hint = 0x0; - - /* TODO - do callout here to get the status */ - - memset(command, 0, sizeof(command)); - slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR, *svcname, "status"); - - DEBUG(10, ("enum_external_services: status command is [%s]\n", command)); - - /* TODO - wrap in privilege check */ - - ret = smbrun(command, &fd); - DEBUGADD(10, ("returned [%d]\n", ret)); - close(fd); - if(ret != 0) - DEBUG(10, ("enum_external_services: Command returned [%d]\n", ret)); - services[i].status.state = SVCCTL_STOPPED; - if (ret == 0) { - services[i].status.state = SVCCTL_RUNNING; - services[i].status.controls_accepted = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP; - } else { - services[i].status.state = SVCCTL_STOPPED; - services[i].status.controls_accepted = 0; - } - svcname++; - i++; - } - - DEBUG(10,("enum_external_services: Read services %d\n",num_services)); - *added = num_services; - - return WERR_OK; -} - -/******************************************************************** -********************************************************************/ - -BOOL get_service_info(TDB_CONTEXT *stdb,char *service_name, Service_info *si) -{ - pstring keystring,sn; - TDB_DATA kbuf, dbuf; - - if ((stdb == NULL) || (si == NULL) || (service_name==NULL) || (*service_name == 0)) - return False; - - /* TODO - error handling -- what if the service isn't in the DB? */ - - slprintf(keystring, sizeof(keystring)-1, "SVCCTL/SERVICE_INFO/%s", service_name); - - /* tdb_lock_bystring(stdb, keystring, 0); */ - - DEBUGADD(10, ("_svcctl_read_service_tdb_to_si: Key is [%s]\n", keystring)); - kbuf.dptr = keystring; - kbuf.dsize = strlen(keystring)+1; - dbuf = tdb_fetch(stdb, kbuf); - - if (!dbuf.dptr) { - DEBUGADD(10, ("_svcctl_read_service_tdb_to_si: Could not find record associated with [%s]\n", keystring)); - return False; - } - tdb_unpack(dbuf.dptr, dbuf.dsize, "PPPPPPPPPPP", - sn, - si->servicetype, - si->filename, - si->provides, - si->dependencies, - si->shouldstart, - si->shouldstop, - si->requiredstart, - si->requiredstop, - si->description, - si->shortdescription); - - SAFE_FREE(dbuf.dptr); - - return True; -} - -/********************************************************************* -*********************************************************************/ - -BOOL store_service_info(TDB_CONTEXT *stdb,char *service_name, Service_info *si) -{ - pstring keystring; - pstring pbuf; - int len; - TDB_DATA kbuf,dbuf; - - /* Note -- when we write to the tdb, we "index" on the filename field, not the nice name. - when a service is "opened", it is opened by the nice (SERVICENAME) name, not the file name. So there needs to be a mapping from - nice name back to the file name. */ - - if ((stdb == NULL) || (si == NULL) || (service_name==NULL) || (*service_name == 0)) - return False; - - /* todo - mayke the service type an ENUM, add any security descriptor structures into it */ - - len= tdb_pack(pbuf,sizeof(pbuf),"PPPPPPPPPPP", - service_name,si->servicetype,si->filename,si->provides,si->dependencies, - si->shouldstart,si->shouldstop,si->requiredstart,si->requiredstop,si->description, - (si->shortdescription && (0 != strlen(si->shortdescription))?si->shortdescription:si->description)); - if (len > sizeof(pbuf)) { - /* todo error here */ - return False; - } - - slprintf(keystring, sizeof(keystring)-1, "SVCCTL/SERVICE_INFO/%s", service_name); - DEBUGADD(10, ("_svcctl_write_si_to_service_tdb: Key is [%s]\n", keystring)); - kbuf.dsize = strlen(keystring)+1; - kbuf.dptr = keystring; - dbuf.dsize = len; - dbuf.dptr = pbuf; - - return (tdb_store(stdb, kbuf, dbuf, TDB_REPLACE) == 0); -} - - -#endif - /******************************************************************** ********************************************************************/ @@ -297,9 +65,9 @@ static SEC_DESC* construct_service_sd( TALLOC_CTX *ctx ) static void fill_service_values( const char *name, REGVAL_CTR *values ) { - UNISTR2 data, dname, ipath; + UNISTR2 data, dname, ipath, description; uint32 dword; - pstring path; + pstring pstr; /* These values are hardcoded in all QueryServiceConfig() replies. I'm just storing them here for cosmetic purposes */ @@ -321,27 +89,32 @@ static void fill_service_values( const char *name, REGVAL_CTR *values ) /* special considerations for internal services and the DisplayName value */ if ( strequal(name, "Spooler") ) { - pstr_sprintf( path, "%s/%s/smbd",dyn_LIBDIR, SVCCTL_SCRIPT_DIR ); - init_unistr2( &ipath, path, UNI_STR_TERMINATE ); + pstr_sprintf( pstr, "%s/%s/smbd",dyn_LIBDIR, SVCCTL_SCRIPT_DIR ); + init_unistr2( &ipath, pstr, UNI_STR_TERMINATE ); + init_unistr2( &description, "Internal service for spooling files to print devices", UNI_STR_TERMINATE ); init_unistr2( &dname, "Print Spooler", UNI_STR_TERMINATE ); } else if ( strequal(name, "NETLOGON") ) { - pstr_sprintf( path, "%s/%s/smbd",dyn_LIBDIR, SVCCTL_SCRIPT_DIR ); - init_unistr2( &ipath, path, UNI_STR_TERMINATE ); + pstr_sprintf( pstr, "%s/%s/smbd",dyn_LIBDIR, SVCCTL_SCRIPT_DIR ); + init_unistr2( &ipath, pstr, UNI_STR_TERMINATE ); + init_unistr2( &description, "File service providing access to policy and profile data", UNI_STR_TERMINATE ); init_unistr2( &dname, "Net Logon", UNI_STR_TERMINATE ); } else if ( strequal(name, "RemoteRegistry") ) { - pstr_sprintf( path, "%s/%s/smbd",dyn_LIBDIR, SVCCTL_SCRIPT_DIR ); - init_unistr2( &ipath, path, UNI_STR_TERMINATE ); + pstr_sprintf( pstr, "%s/%s/smbd",dyn_LIBDIR, SVCCTL_SCRIPT_DIR ); + init_unistr2( &ipath, pstr, UNI_STR_TERMINATE ); + init_unistr2( &description, "Internal service providing remote access to the Samba registry", UNI_STR_TERMINATE ); init_unistr2( &dname, "Remote Registry Service", UNI_STR_TERMINATE ); } else { - pstr_sprintf( path, "%s/%s/%s",dyn_LIBDIR, SVCCTL_SCRIPT_DIR, name ); - init_unistr2( &ipath, path, UNI_STR_TERMINATE ); + pstr_sprintf( pstr, "%s/%s/%s",dyn_LIBDIR, SVCCTL_SCRIPT_DIR, name ); + init_unistr2( &ipath, pstr, UNI_STR_TERMINATE ); + init_unistr2( &description, "External Unix Service", UNI_STR_TERMINATE ); init_unistr2( &dname, name, UNI_STR_TERMINATE ); } regval_ctr_addvalue( values, "DisplayName", REG_SZ, (char*)dname.buffer, dname.uni_str_len*2); regval_ctr_addvalue( values, "ImagePath", REG_SZ, (char*)ipath.buffer, ipath.uni_str_len*2); + regval_ctr_addvalue( values, "Description", REG_SZ, (char*)description.buffer, description.uni_str_len*2); return; } @@ -446,7 +219,7 @@ static void add_new_svc_name( REGISTRY_KEY *key_parent, REGSUBKEY_CTR *subkeys, void svcctl_init_keys( void ) { - const char **service_list = lp_enable_svcctl(); + const char **service_list = lp_svcctl_list(); int i; REGSUBKEY_CTR *subkeys; REGISTRY_KEY *key = NULL; @@ -604,6 +377,46 @@ char* svcctl_lookup_dispname( const char *name, NT_USER_TOKEN *token ) return display_name; } +/******************************************************************** +********************************************************************/ + +char* svcctl_lookup_description( const char *name, NT_USER_TOKEN *token ) +{ + static fstring description; + REGISTRY_KEY *key; + REGVAL_CTR *values; + REGISTRY_VALUE *val; + pstring path; + WERROR wresult; + + /* now add the security descriptor */ + + pstr_sprintf( path, "%s\\%s", KEY_SERVICES, name ); + wresult = regkey_open_internal( &key, path, token, REG_KEY_ALL ); + if ( !W_ERROR_IS_OK(wresult) ) { + DEBUG(0,("svcctl_lookup_dispname: key lookup failed! [%s] (%s)\n", + path, dos_errstr(wresult))); + return NULL; + } + + if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) { + DEBUG(0,("svcctl_lookup_dispname: talloc() failed!\n")); + TALLOC_FREE( key ); + return NULL; + } + + fetch_reg_values( key, values ); + + if ( !(val = regval_ctr_getvalue( values, "Description" )) ) + fstrcpy( description, "Unix Service"); + else + rpcstr_pull( description, regval_data_p(val), sizeof(description), regval_size(val), 0 ); + + TALLOC_FREE( key ); + + return description; +} + /******************************************************************** ********************************************************************/ -- 2.11.4.GIT