From 2851e43e4881485b0af418975eca8f01ab27ca3b Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Wed, 15 Jun 2005 00:54:43 +0000 Subject: r7595: start trying to split out the svcctl functions into separate files for better maintenance; add SERVICE_CONTROL_OPS for spoolss service (This used to be commit 2b0ea30a1a3aebaabd5d328de50e6ad2ef18d45d) --- source3/Makefile.in | 3 +- source3/include/rpc_svcctl.h | 4 +- source3/rpc_server/srv_svcctl_nt.c | 705 +------------------------------------ source3/services/services_db.c | 573 ++++++++++++++++++++++++++++++ source3/services/svc_rcinit.c | 204 +++++++++++ source3/services/svc_spoolss.c | 58 +++ 6 files changed, 853 insertions(+), 694 deletions(-) create mode 100644 source3/services/services_db.c create mode 100644 source3/services/svc_rcinit.c create mode 100644 source3/services/svc_spoolss.c diff --git a/source3/Makefile.in b/source3/Makefile.in index 1bac47f919..2e29b94dfc 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -276,7 +276,8 @@ RPC_SVC_OBJ = rpc_server/srv_srvsvc.o rpc_server/srv_srvsvc_nt.o RPC_WKS_OBJ = rpc_server/srv_wkssvc.o rpc_server/srv_wkssvc_nt.o -RPC_SVCCTL_OBJ = rpc_server/srv_svcctl.o rpc_server/srv_svcctl_nt.o +RPC_SVCCTL_OBJ = rpc_server/srv_svcctl.o rpc_server/srv_svcctl_nt.o \ + services/svc_spoolss.o services/svc_rcinit.o services/services_db.o RPC_DFS_OBJ = rpc_server/srv_dfs.o rpc_server/srv_dfs_nt.o diff --git a/source3/include/rpc_svcctl.h b/source3/include/rpc_svcctl.h index c49d536e49..ede5d65565 100644 --- a/source3/include/rpc_svcctl.h +++ b/source3/include/rpc_svcctl.h @@ -111,6 +111,8 @@ #define SVC_STATUS_PROCESS_INFO 0x00000001 +#define SVCCTL_SCRIPT_DIR "/svcctl/" + /* utility structures for RPCs */ typedef struct { @@ -204,7 +206,7 @@ typedef struct { /* functions for enumerating subkeys and values */ WERROR (*stop_service)( void ); WERROR (*start_service) ( void ); - BOOL (*service_status)( SERVICE_STATUS *status ); + WERROR (*service_status)( SERVICE_STATUS *status ); } SERVICE_CONTROL_OPS; /* structure to store the service handle information */ diff --git a/source3/rpc_server/srv_svcctl_nt.c b/source3/rpc_server/srv_svcctl_nt.c index 3367768f81..e9f60e887c 100644 --- a/source3/rpc_server/srv_svcctl_nt.c +++ b/source3/rpc_server/srv_svcctl_nt.c @@ -37,700 +37,20 @@ #define SVCCTL_SCRIPT_DIR "/svcctl/" -/* - * sertup the \PIPE\svcctl db API - */ - -#define SCVCTL_DATABASE_VERSION_V1 1 -static TDB_CONTEXT *service_tdb; /* used for services tdb file */ - -/* there are two types of services -- internal, and external. - Internal services are "built-in" to samba -- there may be - functions that exist to provide the control and enumeration - functions. There certainly is information returned to be - displayed in the typical management console. - - External services are those that can be specified in the smb.conf - file -- and they conform to the LSB specification as to having - particular keywords in the scripts. Note that these "scripts" are - located in the lib directory, and are likely links to LSB-compliant - init.d scripts, such as those that might come with Suse. Note - that the spec is located http://www.linuxbase.org/spec/ */ - - -/* Expand this to include what can and can't be done - with a particular internal service. Expand as necessary - to add other infromation like what can be controlled, - etc. */ - -typedef struct Internal_service_struct -{ - const char *filename; /* internal name "index" */ - const char *displayname; - const char *description; - const uint32 statustype; - void *status_fn; - void *control_fn; -} Internal_service_description; - - -static const Internal_service_description ISD[] = { - { "NETLOGON", "Net Logon", "Provides logon and authentication service to the network", 0x110, NULL, NULL}, - { "Spooler", "Spooler", "Printing Services", 0x0020, NULL, NULL}, - { NULL, NULL, NULL, 0, NULL, NULL} +struct service_control_op_table { + const char *name; + SERVICE_CONTROL_OPS *ops; }; +extern SERVICE_CONTROL_OPS spoolss_svc_ops; -/******************************************************************** - TODOs - (a) get and set security descriptors on services - (b) read and write QUERY_SERVICE_CONFIG structures (both kinds, country and western) - (c) create default secdesc objects for services and SCM - (d) check access control masks with se_access_check() -********************************************************************/ - -#if 0 -/********************************************************************* - given a service nice name, find the underlying service name -*********************************************************************/ - -static BOOL convert_service_displayname(TDB_CONTEXT *stdb,pstring service_nicename, pstring servicename,int szsvcname) -{ - pstring keystring; - TDB_DATA key_data; - - if ((stdb == NULL) || (service_nicename==NULL) || (servicename == NULL)) - return False; - - pstr_sprintf(keystring,"SERVICE_NICENAME/%s", servicename); - - DEBUG(5, ("convert_service_displayname: Looking for service name [%s], key [%s]\n", - service_nicename, keystring)); - - key_data = tdb_fetch_bystring(stdb,keystring); - - if (key_data.dsize == 0) { - DEBUG(5, ("convert_service_displayname: [%s] Not found, tried key [%s]\n",service_nicename,keystring)); - return False; - } - - strncpy(servicename,key_data.dptr,szsvcname); - servicename[(key_data.dsize > szsvcname ? szsvcname : key_data.dsize)] = 0; - DEBUG(5, ("convert_service_displayname: Found service name [%s], name is [%s]\n", - service_nicename,servicename)); - - return True; -} -#endif - -/******************************************************************************* - Get the INTERNAL services information for the given service name. -*******************************************************************************/ - -static BOOL get_internal_service_data(const Internal_service_description *isd, Service_info *si) -{ - ZERO_STRUCTP( si ); -#if 0 - - pstrcpy( si->servicename, isd->displayname); - pstrcpy( si->servicetype, "INTERNAL"); - pstrcpy( si->filename, isd->filename); - pstrcpy( si->provides, isd->displayname); - pstrcpy( si->description, isd->description); - pstrcpy( si->shortdescription, isd->description); -#endif - - return True; -} - - -/******************************************************************************* - Get the services information by reading and parsing the shell scripts. These - are symbolically linked into the SVCCTL_SCRIPT_DIR directory. - - Get the names of the services/scripts to read from the smb.conf file. -*******************************************************************************/ - -static BOOL get_LSB_data(char *fname,Service_info *si ) -{ - pstring initdfile; - char mybuffer[256]; - const char *tokenptr; - char **qlines; - int fd = -1; - int nlines, *numlines,i,in_section,in_description; - - pstrcpy(si->servicename,""); - pstrcpy(si->servicetype,"EXTERNAL"); - pstrcpy(si->filename,fname); - pstrcpy(si->provides,""); - pstrcpy(si->dependencies,""); - pstrcpy(si->shouldstart,""); - pstrcpy(si->shouldstop,""); - pstrcpy(si->requiredstart,""); - pstrcpy(si->requiredstop,""); - pstrcpy(si->description,""); - pstrcpy(si->shortdescription,""); - - numlines = &nlines; - in_section = 0; - in_description = 0; - - - if( !fname || !*fname ) { - DEBUG(0, ("Must define an \"LSB-style init file\" to read.\n")); - return False; - } - pstrcpy(initdfile,dyn_LIBDIR); - pstrcat(initdfile,SVCCTL_SCRIPT_DIR); - pstrcat(initdfile,fname); - - /* TODO - should check to see if the file that we're trying to open is - actually a script. If it's NOT, we should do something like warn, - and not continue to try to find info we're looking for */ - - DEBUG(10, ("Opening [%s]\n", initdfile)); - fd = -1; - fd = open(initdfile,O_RDONLY); - *numlines = 0; - - if (fd == -1) { - DEBUG(10, ("Couldn't open [%s]\n", initdfile)); - return False; - } - - qlines = fd_lines_load(fd, numlines); - DEBUGADD(10, ("Lines returned = [%d]\n", *numlines)); - close(fd); - - - if (*numlines) { - - for(i = 0; i < *numlines; i++) { - - DEBUGADD(10, ("Line[%d] = %s\n", i, qlines[i])); - if (!in_section && (0==strwicmp("### BEGIN INIT INFO", qlines[i]))) { - /* we now can look for params */ - DEBUGADD(10, ("Configuration information starts on line = [%d]\n", i)); - in_section = 1; - - } else if (in_section && (0==strwicmp("### END INIT INFO", qlines[i]))) { - DEBUGADD(10, ("Configuration information ends on line = [%d]\n", i)); - DEBUGADD(10, ("Description is [%s]\n", si->description)); - in_description = 0; - in_section = 0; - break; - } else if (in_section) { - tokenptr = qlines[i]; - if (in_description) { - DEBUGADD(10, ("Processing DESCRIPTION [%d]\n", *tokenptr)); - if (tokenptr && (*tokenptr=='#') && (*(tokenptr+1)=='\t')) { - DEBUGADD(10, ("Adding to DESCRIPTION [%d]\n", *tokenptr)); - pstrcat(si->description," "); - pstrcat(si->description,tokenptr+2); - continue; - } - in_description = 0; - DEBUGADD(10, ("Not a description!\n")); - } - if (!next_token(&tokenptr,mybuffer," \t",sizeof(mybuffer))) { - DEBUGADD(10, ("Invalid line [%d]\n", i)); - break; /* bad line? */ - } - if (0 != strncmp(mybuffer,"#",1)) { - DEBUGADD(10, ("Invalid line [%d], is %s\n", i,mybuffer)); - break; - } - if (!next_token(&tokenptr,mybuffer," \t",sizeof(mybuffer))) { - DEBUGADD(10, ("Invalid token on line [%d]\n", i)); - break; /* bad line? */ - } - DEBUGADD(10, ("Keyword is [%s]\n", mybuffer)); - if (0==strwicmp(mybuffer,"Description:")) { - while (tokenptr && *tokenptr && (strchr(" \t",*tokenptr))) { - tokenptr++; - } - pstrcpy(si->description,tokenptr); - DEBUGADD(10, ("FOUND DESCRIPTION! Data is [%s]\n", tokenptr)); - in_description = 1; - } else { - while (tokenptr && *tokenptr && (strchr(" \t",*tokenptr))) { - tokenptr++; - } - DEBUGADD(10, ("Data is [%s]\n", tokenptr)); - in_description = 0; - - /* save certain keywords, don't save others */ - if (0==strwicmp(mybuffer, "Provides:")) { - pstrcpy(si->provides,tokenptr); - pstrcpy(si->servicename,tokenptr); - } - - if (0==strwicmp(mybuffer, "Short-Description:")) { - pstrcpy(si->shortdescription,tokenptr); - } - - if (0==strwicmp(mybuffer, "Required-start:")) { - pstrcpy(si->requiredstart,tokenptr); - pstrcpy(si->dependencies,tokenptr); - } - - if (0==strwicmp(mybuffer, "Should-start:")) { - pstrcpy(si->shouldstart,tokenptr); - } - } - } - } - - file_lines_free(qlines); - return True; - } - - return False; -} - -/******************************************************************** -********************************************************************/ - -static BOOL get_service_info(TDB_CONTEXT *stdb,char *service_name, Service_info *si) -{ - - pstring keystring; - TDB_DATA key_data; - - 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? */ - - pstr_sprintf(keystring,"SERVICE/%s/TYPE", service_name); - key_data = tdb_fetch_bystring(stdb,keystring); - strncpy(si->servicetype,key_data.dptr,key_data.dsize); - si->servicetype[key_data.dsize] = 0; - - /* crude check to see if the service exists... */ - DEBUG(3,("Size of the TYPE field is %d\n",key_data.dsize)); - if (key_data.dsize == 0) - return False; - - pstr_sprintf(keystring,"SERVICE/%s/FILENAME", service_name); - key_data = tdb_fetch_bystring(stdb,keystring); - strncpy(si->filename,key_data.dptr,key_data.dsize); - si->filename[key_data.dsize] = 0; - - pstr_sprintf(keystring,"SERVICE/%s/PROVIDES", service_name); - key_data = tdb_fetch_bystring(stdb,keystring); - strncpy(si->provides,key_data.dptr,key_data.dsize); - si->provides[key_data.dsize] = 0; - strncpy(si->servicename,key_data.dptr,key_data.dsize); - si->servicename[key_data.dsize] = 0; - - - pstr_sprintf(keystring,"SERVICE/%s/DEPENDENCIES", service_name); - key_data = tdb_fetch_bystring(stdb,keystring); - strncpy(si->dependencies,key_data.dptr,key_data.dsize); - si->dependencies[key_data.dsize] = 0; - - pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTART", service_name); - key_data = tdb_fetch_bystring(stdb,keystring); - strncpy(si->shouldstart,key_data.dptr,key_data.dsize); - si->shouldstart[key_data.dsize] = 0; - - pstr_sprintf(keystring,"SERVICE/%s/SHOULD_STOP", service_name); - key_data = tdb_fetch_bystring(stdb,keystring); - strncpy(si->shouldstop,key_data.dptr,key_data.dsize); - si->shouldstop[key_data.dsize] = 0; - - pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTART", service_name); - key_data = tdb_fetch_bystring(stdb,keystring); - strncpy(si->requiredstart,key_data.dptr,key_data.dsize); - si->requiredstart[key_data.dsize] = 0; - - pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTOP", service_name); - key_data = tdb_fetch_bystring(stdb,keystring); - strncpy(si->requiredstop,key_data.dptr,key_data.dsize); - si->requiredstop[key_data.dsize] = 0; - - pstr_sprintf(keystring,"SERVICE/%s/DESCRIPTION", service_name); - key_data = tdb_fetch_bystring(stdb,keystring); - strncpy(si->description,key_data.dptr,key_data.dsize); - si->description[key_data.dsize] = 0; - - pstr_sprintf(keystring,"SERVICE/%s/SHORTDESC", service_name); - key_data = tdb_fetch_bystring(stdb,keystring); - strncpy(si->shortdescription,key_data.dptr,key_data.dsize); - si->shortdescription[key_data.dsize] = 0; - - return True; -} - -/********************************************************************* -*********************************************************************/ - -static BOOL store_service_info(TDB_CONTEXT *stdb,char *service_name, Service_info *si) -{ - pstring keystring; - - /* 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; - - - /* Store the nicename */ - - pstr_sprintf(keystring,"SERVICE_NICENAME/%s", si->servicename); - tdb_store_bystring(stdb,keystring,string_tdb_data(service_name),TDB_REPLACE); - - pstr_sprintf(keystring,"SERVICE/%s/TYPE", service_name); - tdb_store_bystring(stdb,keystring,string_tdb_data(si->servicetype),TDB_REPLACE); - - pstr_sprintf(keystring,"SERVICE/%s/FILENAME", service_name); - tdb_store_bystring(stdb,keystring,string_tdb_data(si->filename),TDB_REPLACE); - - pstr_sprintf(keystring,"SERVICE/%s/PROVIDES", service_name); - tdb_store_bystring(stdb,keystring,string_tdb_data(si->provides),TDB_REPLACE); - - pstr_sprintf(keystring,"SERVICE/%s/SERVICENAME", service_name); - tdb_store_bystring(stdb,keystring,string_tdb_data(si->servicename),TDB_REPLACE); - - pstr_sprintf(keystring,"SERVICE/%s/DEPENDENCIES", service_name); - tdb_store_bystring(stdb,keystring,string_tdb_data(si->dependencies),TDB_REPLACE); - - pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTART", service_name); - tdb_store_bystring(stdb,keystring,string_tdb_data(si->shouldstart),TDB_REPLACE); - - pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTOP", service_name); - tdb_store_bystring(stdb,keystring,string_tdb_data(si->shouldstop),TDB_REPLACE); - - pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTART", service_name); - tdb_store_bystring(stdb,keystring,string_tdb_data(si->requiredstart),TDB_REPLACE); - - pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTOP", service_name); - tdb_store_bystring(stdb,keystring,string_tdb_data(si->requiredstop),TDB_REPLACE); - - pstr_sprintf(keystring,"SERVICE/%s/DESCRIPTION", service_name); - tdb_store_bystring(stdb,keystring,string_tdb_data(si->description),TDB_REPLACE); - - pstr_sprintf(keystring,"SERVICE/%s/SHORTDESC", service_name); - tdb_lock_bystring(stdb, keystring, 0); - if (si->shortdescription && *si->shortdescription) - tdb_store_bystring(stdb,keystring,string_tdb_data(si->shortdescription),TDB_REPLACE); - else - tdb_store_bystring(stdb,keystring,string_tdb_data(si->description),TDB_REPLACE); - - return True; -} - -/******************************************************************** - allocate an array of external services and return them. Null return - is okay, make sure &added is also zero! -********************************************************************/ - -static int num_external_services(void) -{ - int num_services; - char **svc_list; - pstring keystring, external_services_string; - TDB_DATA key_data; - - - if (!service_tdb) { - DEBUG(8,("enum_external_services: service database is not open!!!\n")); - num_services = 0; - } else { - pstrcpy(keystring,"EXTERNAL_SERVICES"); - tdb_lock_bystring(service_tdb, keystring, 0); - 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,key_data.dsize)); - } - tdb_unlock_bystring(service_tdb, keystring); - } - svc_list = str_list_make(external_services_string,NULL); - - num_services = str_list_count( (const char **)svc_list); - - return num_services; -} - - - -/******************************************************************** - 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. -********************************************************************/ - -static 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"); - tdb_lock_bystring(service_tdb, keystring, 0); - 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,key_data.dsize)); - } - tdb_unlock_bystring(service_tdb, keystring); - } - 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; - } - -#if 0 -/* *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; - } -#endif - - 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; -} - -int num_internal_services(void) -{ - int num_services; - char **svc_list; - pstring keystring, internal_services_string; - TDB_DATA key_data; - - if (!service_tdb) { - DEBUG(8,("enum_internal_services: service database is not open!!!\n")); - num_services = 0; - } else { - pstrcpy(keystring,"INTERNAL_SERVICES"); - tdb_lock_bystring(service_tdb, keystring, 0); - key_data = tdb_fetch_bystring(service_tdb, keystring); - - if ((key_data.dptr != NULL) && (key_data.dsize != 0)) { - strncpy(internal_services_string,key_data.dptr,key_data.dsize); - internal_services_string[key_data.dsize] = 0; - DEBUG(8,("enum_internal_services: services list is %s, size is %d\n",internal_services_string,key_data.dsize)); - } - tdb_unlock_bystring(service_tdb, keystring); - } - svc_list = str_list_make(internal_services_string,NULL); - - num_services = str_list_count( (const char **)svc_list); - - return num_services; -} - -/**************************************************************************** - Create/Open the service control manager tdb. This code a clone of init_group_mapping. -****************************************************************************/ - -BOOL init_svcctl_db(void) -{ - const char *vstring = "INFO/version"; - uint32 vers_id; - char **svc_list; - char **svcname; - pstring keystring; - pstring external_service_list; - pstring internal_service_list; - Service_info si; - const Internal_service_description *isd_ptr; - /* svc_list = str_list_make( "etc/init.d/skeleton etc/init.d/syslog", NULL ); */ - svc_list=(char **)lp_enable_svcctl(); - - if (service_tdb) - return True; - - pstrcpy(external_service_list,""); - - service_tdb = tdb_open_log(lock_path("services.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600); - if (!service_tdb) { - DEBUG(0,("Failed to open service db\n")); - service_tdb = tdb_open_log(lock_path("services.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); - if (!service_tdb) return False; - DEBUG(0,("Created new services db\n")); - } - - if ((-1 == tdb_fetch_uint32(service_tdb, vstring,&vers_id)) || (vers_id != SERVICEDB_VERSION_V1)) { - /* wrong version of DB, or db was just created */ - tdb_traverse(service_tdb, tdb_traverse_delete_fn, NULL); - tdb_store_uint32(service_tdb, vstring, SERVICEDB_VERSION_V1); - } - tdb_unlock_bystring(service_tdb, vstring); - - DEBUG(0,("Initializing services db\n")); - - svcname = svc_list; - - /* Get the EXTERNAL services as mentioned by line in smb.conf */ - - while (*svcname) { - DEBUG(10,("Reading information on service %s\n",*svcname)); - if (get_LSB_data(*svcname,&si));{ - /* write the information to the TDB */ - store_service_info(service_tdb,*svcname,&si); - /* definitely not efficient to do it this way. */ - pstrcat(external_service_list,"\""); - pstrcat(external_service_list,*svcname); - pstrcat(external_service_list,"\" "); - } - svcname++; - } - pstrcpy(keystring,"EXTERNAL_SERVICES"); - tdb_lock_bystring(service_tdb, keystring, 0); - DEBUG(8,("Storing external service list [%s]\n",external_service_list)); - tdb_store_bystring(service_tdb,keystring,string_tdb_data(external_service_list),TDB_REPLACE); - tdb_unlock_bystring(service_tdb,keystring); - - /* Get the INTERNAL services */ - - pstrcpy(internal_service_list,""); - isd_ptr = ISD; - - while (isd_ptr && (isd_ptr->filename)) { - DEBUG(10,("Reading information on service %s\n",isd_ptr->filename)); - if (get_internal_service_data(isd_ptr,&si)){ - /* write the information to the TDB */ - store_service_info(service_tdb,(char *)isd_ptr->filename,&si); - /* definitely not efficient to do it this way. */ - pstrcat(internal_service_list,"\""); - pstrcat(internal_service_list,isd_ptr->filename); - pstrcat(internal_service_list,"\" "); - - } - isd_ptr++; - } - pstrcpy(keystring,"INTERNAL_SERVICES"); - tdb_lock_bystring(service_tdb, keystring, 0); - DEBUG(8,("Storing internal service list [%s]\n",internal_service_list)); - tdb_store_bystring(service_tdb,keystring,string_tdb_data(internal_service_list),TDB_REPLACE); - tdb_unlock_bystring(service_tdb,keystring); +struct service_control_op_table svcctl_ops[] = { + { "Spooler", &spoolss_svc_ops }, + { "NETLOGON", NULL }, + { NULL, NULL } +}; - return True; -} /******************************************************************** ********************************************************************/ @@ -862,6 +182,8 @@ static WERROR create_open_service_handle( pipes_struct *p, POLICY_HND *handle, if ( !service ) { info->type = SVC_HANDLE_IS_SCM; } else { + int i; + info->type = SVC_HANDLE_IS_SERVICE; if ( !(info->name = SMB_STRDUP( service )) ) { @@ -869,13 +191,12 @@ static WERROR create_open_service_handle( pipes_struct *p, POLICY_HND *handle, WERR_NOMEM; } -#if 0 /* lookup the SERVICE_CONTROL_OPS */ for ( i=0; svcctl_ops[i].name; i++ ) { - ;; + if ( strequal( svcctl_ops[i].name, service ) ) + info->ops = svcctl_ops[i].ops; } -#endif } info->access_granted = access_granted; diff --git a/source3/services/services_db.c b/source3/services/services_db.c new file mode 100644 index 0000000000..df74387959 --- /dev/null +++ b/source3/services/services_db.c @@ -0,0 +1,573 @@ +/* + * Unix SMB/CIFS implementation. + * Service Control API Implementation + * Copyright (C) Gerald Carter 2005. + * Copyright (C) Marcin Krzysztof Porwit 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 + * 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 02139, USA. + */ + +#include "includes.h" + +/* backend database routines for services.tdb */ + +#define SERVICEDB_VERSION_V1 1 /* Will there be more? */ +#define INTERNAL_SERVICES_LIST "NETLOGON Spooler" + +/* */ +/* scripts will execute from the following libdir, if they are in the enable svcctl= */ +/* these should likely be symbolic links. Note that information about them will be extracted from the files themselves */ +/* using the LSB standard keynames for various information */ + +#define SCVCTL_DATABASE_VERSION_V1 1 +static TDB_CONTEXT *service_tdb; /* used for services tdb file */ + +/* there are two types of services -- internal, and external. + Internal services are "built-in" to samba -- there may be + functions that exist to provide the control and enumeration + functions. There certainly is information returned to be + displayed in the typical management console. + + External services are those that can be specified in the smb.conf + file -- and they conform to the LSB specification as to having + particular keywords in the scripts. Note that these "scripts" are + located in the lib directory, and are likely links to LSB-compliant + init.d scripts, such as those that might come with Suse. Note + that the spec is located http://www.linuxbase.org/spec/ */ + + + +/* Expand this to include what can and can't be done + with a particular internal service. Expand as necessary + to add other infromation like what can be controlled, + etc. */ + +typedef struct Internal_service_struct +{ + const char *filename; /* internal name "index" */ + const char *displayname; + const char *description; + const uint32 statustype; + void *status_fn; + void *control_fn; +} Internal_service_description; + + +static const Internal_service_description ISD[] = { + { "NETLOGON", "Net Logon", "Provides logon and authentication service to the network", 0x110, NULL, NULL}, + { "Spooler", "Spooler", "Printing Services", 0x0020, NULL, NULL}, + { NULL, NULL, NULL, 0, NULL, NULL} +}; + + +/******************************************************************** + allocate an array of external services and return them. Null return + is okay, make sure &added is also zero! +********************************************************************/ + +int num_external_services(void) +{ + int num_services; + char **svc_list; + pstring keystring, external_services_string; + TDB_DATA key_data; + + + if (!service_tdb) { + DEBUG(8,("enum_external_services: service database is not open!!!\n")); + num_services = 0; + } else { + pstrcpy(keystring,"EXTERNAL_SERVICES"); + tdb_lock_bystring(service_tdb, keystring, 0); + 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,key_data.dsize)); + } + tdb_unlock_bystring(service_tdb, keystring); + } + svc_list = str_list_make(external_services_string,NULL); + + num_services = str_list_count( (const char **)svc_list); + + return num_services; +} + + + +/******************************************************************** + 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"); + tdb_lock_bystring(service_tdb, keystring, 0); + 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,key_data.dsize)); + } + tdb_unlock_bystring(service_tdb, keystring); + } + 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; + } + +#if 0 +/* *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; + } +#endif + + 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; +} + +/******************************************************************** +********************************************************************/ + +int num_internal_services(void) +{ + int num_services; + char **svc_list; + pstring keystring, internal_services_string; + TDB_DATA key_data; + + if (!service_tdb) { + DEBUG(8,("enum_internal_services: service database is not open!!!\n")); + num_services = 0; + } else { + pstrcpy(keystring,"INTERNAL_SERVICES"); + tdb_lock_bystring(service_tdb, keystring, 0); + key_data = tdb_fetch_bystring(service_tdb, keystring); + + if ((key_data.dptr != NULL) && (key_data.dsize != 0)) { + strncpy(internal_services_string,key_data.dptr,key_data.dsize); + internal_services_string[key_data.dsize] = 0; + DEBUG(8,("enum_internal_services: services list is %s, size is %d\n",internal_services_string,key_data.dsize)); + } + tdb_unlock_bystring(service_tdb, keystring); + } + svc_list = str_list_make(internal_services_string,NULL); + + num_services = str_list_count( (const char **)svc_list); + + return num_services; +} + +#if 0 +/********************************************************************* + given a service nice name, find the underlying service name +*********************************************************************/ + +static BOOL convert_service_displayname(TDB_CONTEXT *stdb,pstring service_nicename, pstring servicename,int szsvcname) +{ + pstring keystring; + TDB_DATA key_data; + + if ((stdb == NULL) || (service_nicename==NULL) || (servicename == NULL)) + return False; + + pstr_sprintf(keystring,"SERVICE_NICENAME/%s", servicename); + + DEBUG(5, ("convert_service_displayname: Looking for service name [%s], key [%s]\n", + service_nicename, keystring)); + + key_data = tdb_fetch_bystring(stdb,keystring); + + if (key_data.dsize == 0) { + DEBUG(5, ("convert_service_displayname: [%s] Not found, tried key [%s]\n",service_nicename,keystring)); + return False; + } + + strncpy(servicename,key_data.dptr,szsvcname); + servicename[(key_data.dsize > szsvcname ? szsvcname : key_data.dsize)] = 0; + DEBUG(5, ("convert_service_displayname: Found service name [%s], name is [%s]\n", + service_nicename,servicename)); + + return True; +} +#endif + +/******************************************************************************* + Get the INTERNAL services information for the given service name. +*******************************************************************************/ + +static BOOL get_internal_service_data(const Internal_service_description *isd, Service_info *si) +{ + ZERO_STRUCTP( si ); +#if 0 + + pstrcpy( si->servicename, isd->displayname); + pstrcpy( si->servicetype, "INTERNAL"); + pstrcpy( si->filename, isd->filename); + pstrcpy( si->provides, isd->displayname); + pstrcpy( si->description, isd->description); + pstrcpy( si->shortdescription, isd->description); +#endif + + return True; +} + +/******************************************************************** +********************************************************************/ + +BOOL get_service_info(TDB_CONTEXT *stdb,char *service_name, Service_info *si) +{ + + pstring keystring; + TDB_DATA key_data; + + 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? */ + + pstr_sprintf(keystring,"SERVICE/%s/TYPE", service_name); + key_data = tdb_fetch_bystring(stdb,keystring); + strncpy(si->servicetype,key_data.dptr,key_data.dsize); + si->servicetype[key_data.dsize] = 0; + + /* crude check to see if the service exists... */ + DEBUG(3,("Size of the TYPE field is %d\n",key_data.dsize)); + if (key_data.dsize == 0) + return False; + + pstr_sprintf(keystring,"SERVICE/%s/FILENAME", service_name); + key_data = tdb_fetch_bystring(stdb,keystring); + strncpy(si->filename,key_data.dptr,key_data.dsize); + si->filename[key_data.dsize] = 0; + + pstr_sprintf(keystring,"SERVICE/%s/PROVIDES", service_name); + key_data = tdb_fetch_bystring(stdb,keystring); + strncpy(si->provides,key_data.dptr,key_data.dsize); + si->provides[key_data.dsize] = 0; + strncpy(si->servicename,key_data.dptr,key_data.dsize); + si->servicename[key_data.dsize] = 0; + + + pstr_sprintf(keystring,"SERVICE/%s/DEPENDENCIES", service_name); + key_data = tdb_fetch_bystring(stdb,keystring); + strncpy(si->dependencies,key_data.dptr,key_data.dsize); + si->dependencies[key_data.dsize] = 0; + + pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTART", service_name); + key_data = tdb_fetch_bystring(stdb,keystring); + strncpy(si->shouldstart,key_data.dptr,key_data.dsize); + si->shouldstart[key_data.dsize] = 0; + + pstr_sprintf(keystring,"SERVICE/%s/SHOULD_STOP", service_name); + key_data = tdb_fetch_bystring(stdb,keystring); + strncpy(si->shouldstop,key_data.dptr,key_data.dsize); + si->shouldstop[key_data.dsize] = 0; + + pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTART", service_name); + key_data = tdb_fetch_bystring(stdb,keystring); + strncpy(si->requiredstart,key_data.dptr,key_data.dsize); + si->requiredstart[key_data.dsize] = 0; + + pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTOP", service_name); + key_data = tdb_fetch_bystring(stdb,keystring); + strncpy(si->requiredstop,key_data.dptr,key_data.dsize); + si->requiredstop[key_data.dsize] = 0; + + pstr_sprintf(keystring,"SERVICE/%s/DESCRIPTION", service_name); + key_data = tdb_fetch_bystring(stdb,keystring); + strncpy(si->description,key_data.dptr,key_data.dsize); + si->description[key_data.dsize] = 0; + + pstr_sprintf(keystring,"SERVICE/%s/SHORTDESC", service_name); + key_data = tdb_fetch_bystring(stdb,keystring); + strncpy(si->shortdescription,key_data.dptr,key_data.dsize); + si->shortdescription[key_data.dsize] = 0; + + return True; +} + +/********************************************************************* +*********************************************************************/ + +BOOL store_service_info(TDB_CONTEXT *stdb,char *service_name, Service_info *si) +{ + pstring keystring; + + /* 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; + + + /* Store the nicename */ + + pstr_sprintf(keystring,"SERVICE_NICENAME/%s", si->servicename); + tdb_store_bystring(stdb,keystring,string_tdb_data(service_name),TDB_REPLACE); + + pstr_sprintf(keystring,"SERVICE/%s/TYPE", service_name); + tdb_store_bystring(stdb,keystring,string_tdb_data(si->servicetype),TDB_REPLACE); + + pstr_sprintf(keystring,"SERVICE/%s/FILENAME", service_name); + tdb_store_bystring(stdb,keystring,string_tdb_data(si->filename),TDB_REPLACE); + + pstr_sprintf(keystring,"SERVICE/%s/PROVIDES", service_name); + tdb_store_bystring(stdb,keystring,string_tdb_data(si->provides),TDB_REPLACE); + + pstr_sprintf(keystring,"SERVICE/%s/SERVICENAME", service_name); + tdb_store_bystring(stdb,keystring,string_tdb_data(si->servicename),TDB_REPLACE); + + pstr_sprintf(keystring,"SERVICE/%s/DEPENDENCIES", service_name); + tdb_store_bystring(stdb,keystring,string_tdb_data(si->dependencies),TDB_REPLACE); + + pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTART", service_name); + tdb_store_bystring(stdb,keystring,string_tdb_data(si->shouldstart),TDB_REPLACE); + + pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTOP", service_name); + tdb_store_bystring(stdb,keystring,string_tdb_data(si->shouldstop),TDB_REPLACE); + + pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTART", service_name); + tdb_store_bystring(stdb,keystring,string_tdb_data(si->requiredstart),TDB_REPLACE); + + pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTOP", service_name); + tdb_store_bystring(stdb,keystring,string_tdb_data(si->requiredstop),TDB_REPLACE); + + pstr_sprintf(keystring,"SERVICE/%s/DESCRIPTION", service_name); + tdb_store_bystring(stdb,keystring,string_tdb_data(si->description),TDB_REPLACE); + + pstr_sprintf(keystring,"SERVICE/%s/SHORTDESC", service_name); + tdb_lock_bystring(stdb, keystring, 0); + if (si->shortdescription && *si->shortdescription) + tdb_store_bystring(stdb,keystring,string_tdb_data(si->shortdescription),TDB_REPLACE); + else + tdb_store_bystring(stdb,keystring,string_tdb_data(si->description),TDB_REPLACE); + + return True; +} + +/**************************************************************************** + Create/Open the service control manager tdb. This code a clone of init_group_mapping. +****************************************************************************/ + +BOOL init_svcctl_db(void) +{ + const char *vstring = "INFO/version"; + uint32 vers_id; + char **svc_list; + char **svcname; + pstring keystring; + pstring external_service_list; + pstring internal_service_list; + Service_info si; + const Internal_service_description *isd_ptr; + /* svc_list = str_list_make( "etc/init.d/skeleton etc/init.d/syslog", NULL ); */ + svc_list=(char **)lp_enable_svcctl(); + + if (service_tdb) + return True; + + pstrcpy(external_service_list,""); + + service_tdb = tdb_open_log(lock_path("services.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600); + if (!service_tdb) { + DEBUG(0,("Failed to open service db\n")); + service_tdb = tdb_open_log(lock_path("services.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); + if (!service_tdb) return False; + DEBUG(0,("Created new services db\n")); + } + + if ((-1 == tdb_fetch_uint32(service_tdb, vstring,&vers_id)) || (vers_id != SERVICEDB_VERSION_V1)) { + /* wrong version of DB, or db was just created */ + tdb_traverse(service_tdb, tdb_traverse_delete_fn, NULL); + tdb_store_uint32(service_tdb, vstring, SERVICEDB_VERSION_V1); + } + tdb_unlock_bystring(service_tdb, vstring); + + DEBUG(0,("Initializing services db\n")); + + svcname = svc_list; + + /* Get the EXTERNAL services as mentioned by line in smb.conf */ + + while (*svcname) { + DEBUG(10,("Reading information on service %s\n",*svcname)); + if (get_LSB_data(*svcname,&si));{ + /* write the information to the TDB */ + store_service_info(service_tdb,*svcname,&si); + /* definitely not efficient to do it this way. */ + pstrcat(external_service_list,"\""); + pstrcat(external_service_list,*svcname); + pstrcat(external_service_list,"\" "); + } + svcname++; + } + pstrcpy(keystring,"EXTERNAL_SERVICES"); + tdb_lock_bystring(service_tdb, keystring, 0); + DEBUG(8,("Storing external service list [%s]\n",external_service_list)); + tdb_store_bystring(service_tdb,keystring,string_tdb_data(external_service_list),TDB_REPLACE); + tdb_unlock_bystring(service_tdb,keystring); + + /* Get the INTERNAL services */ + + pstrcpy(internal_service_list,""); + isd_ptr = ISD; + + while (isd_ptr && (isd_ptr->filename)) { + DEBUG(10,("Reading information on service %s\n",isd_ptr->filename)); + if (get_internal_service_data(isd_ptr,&si)){ + /* write the information to the TDB */ + store_service_info(service_tdb,(char *)isd_ptr->filename,&si); + /* definitely not efficient to do it this way. */ + pstrcat(internal_service_list,"\""); + pstrcat(internal_service_list,isd_ptr->filename); + pstrcat(internal_service_list,"\" "); + + } + isd_ptr++; + } + pstrcpy(keystring,"INTERNAL_SERVICES"); + tdb_lock_bystring(service_tdb, keystring, 0); + DEBUG(8,("Storing internal service list [%s]\n",internal_service_list)); + tdb_store_bystring(service_tdb,keystring,string_tdb_data(internal_service_list),TDB_REPLACE); + tdb_unlock_bystring(service_tdb,keystring); + + return True; +} + diff --git a/source3/services/svc_rcinit.c b/source3/services/svc_rcinit.c new file mode 100644 index 0000000000..a4046b3511 --- /dev/null +++ b/source3/services/svc_rcinit.c @@ -0,0 +1,204 @@ + +/* + * Unix SMB/CIFS implementation. + * Service Control API Implementation + * Copyright (C) Gerald 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 + * 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 02139, USA. + */ + +#include "includes.h" + +/* Implementation for LSB compliant init scripts */ + +/******************************************************************************* + Get the services information by reading and parsing the shell scripts. These + are symbolically linked into the SVCCTL_SCRIPT_DIR directory. + + Get the names of the services/scripts to read from the smb.conf file. +*******************************************************************************/ + +BOOL get_LSB_data(char *fname,Service_info *si ) +{ + pstring initdfile; + char mybuffer[256]; + const char *tokenptr; + char **qlines; + int fd = -1; + int nlines, *numlines,i,in_section,in_description; + + pstrcpy(si->servicename,""); + pstrcpy(si->servicetype,"EXTERNAL"); + pstrcpy(si->filename,fname); + pstrcpy(si->provides,""); + pstrcpy(si->dependencies,""); + pstrcpy(si->shouldstart,""); + pstrcpy(si->shouldstop,""); + pstrcpy(si->requiredstart,""); + pstrcpy(si->requiredstop,""); + pstrcpy(si->description,""); + pstrcpy(si->shortdescription,""); + + numlines = &nlines; + in_section = 0; + in_description = 0; + + + if( !fname || !*fname ) { + DEBUG(0, ("Must define an \"LSB-style init file\" to read.\n")); + return False; + } + pstrcpy(initdfile,dyn_LIBDIR); + pstrcat(initdfile,SVCCTL_SCRIPT_DIR); + pstrcat(initdfile,fname); + + /* TODO - should check to see if the file that we're trying to open is + actually a script. If it's NOT, we should do something like warn, + and not continue to try to find info we're looking for */ + + DEBUG(10, ("Opening [%s]\n", initdfile)); + fd = -1; + fd = open(initdfile,O_RDONLY); + *numlines = 0; + + if (fd == -1) { + DEBUG(10, ("Couldn't open [%s]\n", initdfile)); + return False; + } + + qlines = fd_lines_load(fd, numlines); + DEBUGADD(10, ("Lines returned = [%d]\n", *numlines)); + close(fd); + + + if (*numlines) { + + for(i = 0; i < *numlines; i++) { + + DEBUGADD(10, ("Line[%d] = %s\n", i, qlines[i])); + if (!in_section && (0==strwicmp("### BEGIN INIT INFO", qlines[i]))) { + /* we now can look for params */ + DEBUGADD(10, ("Configuration information starts on line = [%d]\n", i)); + in_section = 1; + + } else if (in_section && (0==strwicmp("### END INIT INFO", qlines[i]))) { + DEBUGADD(10, ("Configuration information ends on line = [%d]\n", i)); + DEBUGADD(10, ("Description is [%s]\n", si->description)); + in_description = 0; + in_section = 0; + break; + } else if (in_section) { + tokenptr = qlines[i]; + if (in_description) { + DEBUGADD(10, ("Processing DESCRIPTION [%d]\n", *tokenptr)); + if (tokenptr && (*tokenptr=='#') && (*(tokenptr+1)=='\t')) { + DEBUGADD(10, ("Adding to DESCRIPTION [%d]\n", *tokenptr)); + pstrcat(si->description," "); + pstrcat(si->description,tokenptr+2); + continue; + } + in_description = 0; + DEBUGADD(10, ("Not a description!\n")); + } + if (!next_token(&tokenptr,mybuffer," \t",sizeof(mybuffer))) { + DEBUGADD(10, ("Invalid line [%d]\n", i)); + break; /* bad line? */ + } + if (0 != strncmp(mybuffer,"#",1)) { + DEBUGADD(10, ("Invalid line [%d], is %s\n", i,mybuffer)); + break; + } + if (!next_token(&tokenptr,mybuffer," \t",sizeof(mybuffer))) { + DEBUGADD(10, ("Invalid token on line [%d]\n", i)); + break; /* bad line? */ + } + DEBUGADD(10, ("Keyword is [%s]\n", mybuffer)); + if (0==strwicmp(mybuffer,"Description:")) { + while (tokenptr && *tokenptr && (strchr(" \t",*tokenptr))) { + tokenptr++; + } + pstrcpy(si->description,tokenptr); + DEBUGADD(10, ("FOUND DESCRIPTION! Data is [%s]\n", tokenptr)); + in_description = 1; + } else { + while (tokenptr && *tokenptr && (strchr(" \t",*tokenptr))) { + tokenptr++; + } + DEBUGADD(10, ("Data is [%s]\n", tokenptr)); + in_description = 0; + + /* save certain keywords, don't save others */ + if (0==strwicmp(mybuffer, "Provides:")) { + pstrcpy(si->provides,tokenptr); + pstrcpy(si->servicename,tokenptr); + } + + if (0==strwicmp(mybuffer, "Short-Description:")) { + pstrcpy(si->shortdescription,tokenptr); + } + + if (0==strwicmp(mybuffer, "Required-start:")) { + pstrcpy(si->requiredstart,tokenptr); + pstrcpy(si->dependencies,tokenptr); + } + + if (0==strwicmp(mybuffer, "Should-start:")) { + pstrcpy(si->shouldstart,tokenptr); + } + } + } + } + + file_lines_free(qlines); + return True; + } + + return False; +} + +/********************************************************************* +*********************************************************************/ + +static WERROR rcinit_stop( void ) +{ + return WERR_OK; +} + +/********************************************************************* +*********************************************************************/ + +static WERROR rcinit_start( void ) +{ + return WERR_OK; +} + +/********************************************************************* +*********************************************************************/ + +static WERROR rcinit_status( SERVICE_STATUS *service_status ) +{ + return WERR_OK; +} + +/********************************************************************* +*********************************************************************/ + +/* struct for svcctl control to manipulate rcinit service */ + +SERVICE_CONTROL_OPS rcinit_svc_ops = { + rcinit_stop, + rcinit_start, + rcinit_status +}; diff --git a/source3/services/svc_spoolss.c b/source3/services/svc_spoolss.c new file mode 100644 index 0000000000..991bc0fbfd --- /dev/null +++ b/source3/services/svc_spoolss.c @@ -0,0 +1,58 @@ +/* + * Unix SMB/CIFS implementation. + * Service Control API Implementation + * Copyright (C) Gerald 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 + * 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 02139, USA. + */ + +#include "includes.h" + +/* Implementation for internal spoolss service */ + +/********************************************************************* +*********************************************************************/ + +static WERROR spoolss_stop( void ) +{ + return WERR_OK; +} + +/********************************************************************* +*********************************************************************/ + +static WERROR spoolss_start( void ) +{ + return WERR_OK; +} + +/********************************************************************* +*********************************************************************/ + +static WERROR spoolss_status( SERVICE_STATUS *service_status ) +{ + return WERR_OK; +} + +/********************************************************************* +*********************************************************************/ + +/* struct for svcctl control to manipulate spoolss service */ + +SERVICE_CONTROL_OPS spoolss_svc_ops = { + spoolss_stop, + spoolss_start, + spoolss_status +}; -- cgit