2 * Unix SMB/CIFS implementation.
3 * Service Control API Implementation
4 * Copyright (C) Gerald Carter 2005.
5 * Copyright (C) Marcin Krzysztof Porwit 2005.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 /* backend database routines for services.tdb */
26 #define SERVICEDB_VERSION_V1 1 /* Will there be more? */
27 #define INTERNAL_SERVICES_LIST "NETLOGON Spooler"
30 /* scripts will execute from the following libdir, if they are in the enable svcctl=<list of scripts> */
31 /* these should likely be symbolic links. Note that information about them will be extracted from the files themselves */
32 /* using the LSB standard keynames for various information */
34 #define SCVCTL_DATABASE_VERSION_V1 1
35 static TDB_CONTEXT *service_tdb; /* used for services tdb file */
37 /* there are two types of services -- internal, and external.
38 Internal services are "built-in" to samba -- there may be
39 functions that exist to provide the control and enumeration
40 functions. There certainly is information returned to be
41 displayed in the typical management console.
43 External services are those that can be specified in the smb.conf
44 file -- and they conform to the LSB specification as to having
45 particular keywords in the scripts. Note that these "scripts" are
46 located in the lib directory, and are likely links to LSB-compliant
47 init.d scripts, such as those that might come with Suse. Note
48 that the spec is located http://www.linuxbase.org/spec/ */
52 /* Expand this to include what can and can't be done
53 with a particular internal service. Expand as necessary
54 to add other infromation like what can be controlled,
57 typedef struct Internal_service_struct
59 const char *filename; /* internal name "index" */
60 const char *displayname;
61 const char *description;
62 const uint32 statustype;
65 } Internal_service_description;
68 static const Internal_service_description ISD[] = {
69 { "NETLOGON", "Net Logon", "Provides logon and authentication service to the network", 0x110, NULL, NULL},
70 { "Spooler", "Spooler", "Printing Services", 0x0020, NULL, NULL},
71 { NULL, NULL, NULL, 0, NULL, NULL}
75 /********************************************************************
76 allocate an array of external services and return them. Null return
77 is okay, make sure &added is also zero!
78 ********************************************************************/
80 int num_external_services(void)
84 pstring keystring, external_services_string;
89 DEBUG(8,("enum_external_services: service database is not open!!!\n"));
92 pstrcpy(keystring,"EXTERNAL_SERVICES");
93 tdb_lock_bystring(service_tdb, keystring, 0);
94 key_data = tdb_fetch_bystring(service_tdb, keystring);
96 if ((key_data.dptr != NULL) && (key_data.dsize != 0)) {
97 strncpy(external_services_string,key_data.dptr,key_data.dsize);
98 external_services_string[key_data.dsize] = 0;
99 DEBUG(8,("enum_external_services: services list is %s, size is %d\n",external_services_string,key_data.dsize));
101 tdb_unlock_bystring(service_tdb, keystring);
103 svc_list = str_list_make(external_services_string,NULL);
105 num_services = str_list_count( (const char **)svc_list);
112 /********************************************************************
113 Gather information on the "external services". These are services
114 listed in the smb.conf file, and found to exist through checks in
115 this code. Note that added will be incremented on the basis of the
116 number of services added. svc_ptr should have enough memory allocated
117 to accommodate all of the services that exist.
119 Typically num_external_services is used to "size" the amount of
120 memory allocated, but does little/no work.
122 enum_external_services() actually examines each of the specified
123 external services, populates the memory structures, and returns.
125 ** note that 'added' may end up with less than the number of services
126 found in _num_external_services, such as the case when a service is
127 called out, but the actual service doesn't exist or the file can't be
128 read for the service information.
129 ********************************************************************/
131 WERROR enum_external_services(TALLOC_CTX *tcx,ENUM_SERVICES_STATUS **svc_ptr, int existing_services,int *added)
133 /* *svc_ptr must have pre-allocated memory */
134 int num_services = 0;
136 ENUM_SERVICES_STATUS *services=NULL;
137 char **svc_list,**svcname;
138 pstring command, keystring, external_services_string;
144 *added = num_services;
147 DEBUG(8,("enum_external_services: service database is not open!!!\n"));
149 pstrcpy(keystring,"EXTERNAL_SERVICES");
150 tdb_lock_bystring(service_tdb, keystring, 0);
151 key_data = tdb_fetch_bystring(service_tdb, keystring);
152 if ((key_data.dptr != NULL) && (key_data.dsize != 0)) {
153 strncpy(external_services_string,key_data.dptr,key_data.dsize);
154 external_services_string[key_data.dsize] = 0;
155 DEBUG(8,("enum_external_services: services list is %s, size is %d\n",external_services_string,key_data.dsize));
157 tdb_unlock_bystring(service_tdb, keystring);
159 svc_list = str_list_make(external_services_string,NULL);
161 num_services = str_list_count( (const char **)svc_list);
163 if (0 == num_services) {
164 DEBUG(8,("enum_external_services: there are no external services\n"));
165 *added = num_services;
168 DEBUG(8,("enum_external_services: there are [%d] external services\n",num_services));
169 si=TALLOC_ARRAY( tcx, Service_info, 1 );
171 DEBUG(8,("enum_external_services: Failed to alloc si\n"));
176 /* *svc_ptr has the pointer to the array if there is one already. NULL if not. */
177 if ((existing_services>0) && svc_ptr && *svc_ptr) { /* reallocate vs. allocate */
178 DEBUG(8,("enum_external_services: REALLOCing %x to %d services\n", *svc_ptr, existing_services+num_services));
180 services=TALLOC_REALLOC_ARRAY(tcx,*svc_ptr,ENUM_SERVICES_STATUS,existing_services+num_services);
181 DEBUG(8,("enum_external_services: REALLOCed to %x services\n", services));
183 if (!services) return WERR_NOMEM;
186 if ( !(services = TALLOC_ARRAY( tcx, ENUM_SERVICES_STATUS, num_services )) )
191 if (!svc_ptr || !(*svc_ptr))
194 if (existing_services > 0) {
195 i+=existing_services;
199 DEBUG(8,("enum_external_services: enumerating %d external services starting at index %d\n", num_services,existing_services));
202 DEBUG(10,("enum_external_services: Reading information on service %s, index %d\n",*svcname,i));
203 /* get_LSB_data(*svcname,si); */
204 if (!get_service_info(service_tdb,*svcname, si)) {
205 DEBUG(1,("enum_external_services: CAN'T FIND INFO FOR SERVICE %s in the services DB\n",*svcname));
208 if ((si->filename == NULL) || (*si->filename == 0)) {
209 init_unistr(&services[i].servicename, *svcname );
211 init_unistr( &services[i].servicename, si->filename );
212 /* init_unistr( &services[i].servicename, si->servicename ); */
215 if ((si->provides == NULL) || (*si->provides == 0)) {
216 init_unistr(&services[i].displayname, *svcname );
218 init_unistr( &services[i].displayname, si->provides );
221 /* TODO - we could keep the following info in the DB, too... */
223 DEBUG(8,("enum_external_services: Service name [%s] displayname [%s]\n",
224 si->filename, si->provides));
225 services[i].status.type = SVCCTL_WIN32_OWN_PROC;
226 services[i].status.win32_exit_code = 0x0;
227 services[i].status.service_exit_code = 0x0;
228 services[i].status.check_point = 0x0;
229 services[i].status.wait_hint = 0x0;
231 /* TODO - do callout here to get the status */
233 memset(command, 0, sizeof(command));
234 slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR, *svcname, "status");
236 DEBUG(10, ("enum_external_services: status command is [%s]\n", command));
238 /* TODO - wrap in privilege check */
240 ret = smbrun(command, &fd);
241 DEBUGADD(10, ("returned [%d]\n", ret));
244 DEBUG(10, ("enum_external_services: Command returned [%d]\n", ret));
245 services[i].status.state = SVCCTL_STOPPED;
247 services[i].status.state = SVCCTL_RUNNING;
248 services[i].status.controls_accepted = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP;
250 services[i].status.state = SVCCTL_STOPPED;
251 services[i].status.controls_accepted = 0;
257 DEBUG(10,("enum_external_services: Read services %d\n",num_services));
258 *added = num_services;
263 /********************************************************************
264 ********************************************************************/
266 int num_internal_services(void)
270 pstring keystring, internal_services_string;
274 DEBUG(8,("enum_internal_services: service database is not open!!!\n"));
277 pstrcpy(keystring,"INTERNAL_SERVICES");
278 tdb_lock_bystring(service_tdb, keystring, 0);
279 key_data = tdb_fetch_bystring(service_tdb, keystring);
281 if ((key_data.dptr != NULL) && (key_data.dsize != 0)) {
282 strncpy(internal_services_string,key_data.dptr,key_data.dsize);
283 internal_services_string[key_data.dsize] = 0;
284 DEBUG(8,("enum_internal_services: services list is %s, size is %d\n",internal_services_string,key_data.dsize));
286 tdb_unlock_bystring(service_tdb, keystring);
288 svc_list = str_list_make(internal_services_string,NULL);
290 num_services = str_list_count( (const char **)svc_list);
296 /*********************************************************************
297 given a service nice name, find the underlying service name
298 *********************************************************************/
300 static BOOL convert_service_displayname(TDB_CONTEXT *stdb,pstring service_nicename, pstring servicename,int szsvcname)
305 if ((stdb == NULL) || (service_nicename==NULL) || (servicename == NULL))
308 pstr_sprintf(keystring,"SERVICE_NICENAME/%s", servicename);
310 DEBUG(5, ("convert_service_displayname: Looking for service name [%s], key [%s]\n",
311 service_nicename, keystring));
313 key_data = tdb_fetch_bystring(stdb,keystring);
315 if (key_data.dsize == 0) {
316 DEBUG(5, ("convert_service_displayname: [%s] Not found, tried key [%s]\n",service_nicename,keystring));
320 strncpy(servicename,key_data.dptr,szsvcname);
321 servicename[(key_data.dsize > szsvcname ? szsvcname : key_data.dsize)] = 0;
322 DEBUG(5, ("convert_service_displayname: Found service name [%s], name is [%s]\n",
323 service_nicename,servicename));
329 /*******************************************************************************
330 Get the INTERNAL services information for the given service name.
331 *******************************************************************************/
333 static BOOL get_internal_service_data(const Internal_service_description *isd, Service_info *si)
338 pstrcpy( si->servicename, isd->displayname);
339 pstrcpy( si->servicetype, "INTERNAL");
340 pstrcpy( si->filename, isd->filename);
341 pstrcpy( si->provides, isd->displayname);
342 pstrcpy( si->description, isd->description);
343 pstrcpy( si->shortdescription, isd->description);
349 /********************************************************************
350 ********************************************************************/
352 BOOL get_service_info(TDB_CONTEXT *stdb,char *service_name, Service_info *si)
358 if ((stdb == NULL) || (si == NULL) || (service_name==NULL) || (*service_name == 0))
361 /* TODO - error handling -- what if the service isn't in the DB? */
363 pstr_sprintf(keystring,"SERVICE/%s/TYPE", service_name);
364 key_data = tdb_fetch_bystring(stdb,keystring);
365 strncpy(si->servicetype,key_data.dptr,key_data.dsize);
366 si->servicetype[key_data.dsize] = 0;
368 /* crude check to see if the service exists... */
369 DEBUG(3,("Size of the TYPE field is %d\n",key_data.dsize));
370 if (key_data.dsize == 0)
373 pstr_sprintf(keystring,"SERVICE/%s/FILENAME", service_name);
374 key_data = tdb_fetch_bystring(stdb,keystring);
375 strncpy(si->filename,key_data.dptr,key_data.dsize);
376 si->filename[key_data.dsize] = 0;
378 pstr_sprintf(keystring,"SERVICE/%s/PROVIDES", service_name);
379 key_data = tdb_fetch_bystring(stdb,keystring);
380 strncpy(si->provides,key_data.dptr,key_data.dsize);
381 si->provides[key_data.dsize] = 0;
382 strncpy(si->servicename,key_data.dptr,key_data.dsize);
383 si->servicename[key_data.dsize] = 0;
386 pstr_sprintf(keystring,"SERVICE/%s/DEPENDENCIES", service_name);
387 key_data = tdb_fetch_bystring(stdb,keystring);
388 strncpy(si->dependencies,key_data.dptr,key_data.dsize);
389 si->dependencies[key_data.dsize] = 0;
391 pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTART", service_name);
392 key_data = tdb_fetch_bystring(stdb,keystring);
393 strncpy(si->shouldstart,key_data.dptr,key_data.dsize);
394 si->shouldstart[key_data.dsize] = 0;
396 pstr_sprintf(keystring,"SERVICE/%s/SHOULD_STOP", service_name);
397 key_data = tdb_fetch_bystring(stdb,keystring);
398 strncpy(si->shouldstop,key_data.dptr,key_data.dsize);
399 si->shouldstop[key_data.dsize] = 0;
401 pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTART", service_name);
402 key_data = tdb_fetch_bystring(stdb,keystring);
403 strncpy(si->requiredstart,key_data.dptr,key_data.dsize);
404 si->requiredstart[key_data.dsize] = 0;
406 pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTOP", service_name);
407 key_data = tdb_fetch_bystring(stdb,keystring);
408 strncpy(si->requiredstop,key_data.dptr,key_data.dsize);
409 si->requiredstop[key_data.dsize] = 0;
411 pstr_sprintf(keystring,"SERVICE/%s/DESCRIPTION", service_name);
412 key_data = tdb_fetch_bystring(stdb,keystring);
413 strncpy(si->description,key_data.dptr,key_data.dsize);
414 si->description[key_data.dsize] = 0;
416 pstr_sprintf(keystring,"SERVICE/%s/SHORTDESC", service_name);
417 key_data = tdb_fetch_bystring(stdb,keystring);
418 strncpy(si->shortdescription,key_data.dptr,key_data.dsize);
419 si->shortdescription[key_data.dsize] = 0;
424 /*********************************************************************
425 *********************************************************************/
427 BOOL store_service_info(TDB_CONTEXT *stdb,char *service_name, Service_info *si)
431 /* Note -- when we write to the tdb, we "index" on the filename
432 field, not the nice name. when a service is "opened", it is
433 opened by the nice (SERVICENAME) name, not the file name.
434 So there needs to be a mapping from nice name back to the file name. */
436 if ((stdb == NULL) || (si == NULL) || (service_name==NULL) || (*service_name == 0))
440 /* Store the nicename */
442 pstr_sprintf(keystring,"SERVICE_NICENAME/%s", si->servicename);
443 tdb_store_bystring(stdb,keystring,string_tdb_data(service_name),TDB_REPLACE);
445 pstr_sprintf(keystring,"SERVICE/%s/TYPE", service_name);
446 tdb_store_bystring(stdb,keystring,string_tdb_data(si->servicetype),TDB_REPLACE);
448 pstr_sprintf(keystring,"SERVICE/%s/FILENAME", service_name);
449 tdb_store_bystring(stdb,keystring,string_tdb_data(si->filename),TDB_REPLACE);
451 pstr_sprintf(keystring,"SERVICE/%s/PROVIDES", service_name);
452 tdb_store_bystring(stdb,keystring,string_tdb_data(si->provides),TDB_REPLACE);
454 pstr_sprintf(keystring,"SERVICE/%s/SERVICENAME", service_name);
455 tdb_store_bystring(stdb,keystring,string_tdb_data(si->servicename),TDB_REPLACE);
457 pstr_sprintf(keystring,"SERVICE/%s/DEPENDENCIES", service_name);
458 tdb_store_bystring(stdb,keystring,string_tdb_data(si->dependencies),TDB_REPLACE);
460 pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTART", service_name);
461 tdb_store_bystring(stdb,keystring,string_tdb_data(si->shouldstart),TDB_REPLACE);
463 pstr_sprintf(keystring,"SERVICE/%s/SHOULDSTOP", service_name);
464 tdb_store_bystring(stdb,keystring,string_tdb_data(si->shouldstop),TDB_REPLACE);
466 pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTART", service_name);
467 tdb_store_bystring(stdb,keystring,string_tdb_data(si->requiredstart),TDB_REPLACE);
469 pstr_sprintf(keystring,"SERVICE/%s/REQUIREDSTOP", service_name);
470 tdb_store_bystring(stdb,keystring,string_tdb_data(si->requiredstop),TDB_REPLACE);
472 pstr_sprintf(keystring,"SERVICE/%s/DESCRIPTION", service_name);
473 tdb_store_bystring(stdb,keystring,string_tdb_data(si->description),TDB_REPLACE);
475 pstr_sprintf(keystring,"SERVICE/%s/SHORTDESC", service_name);
476 tdb_lock_bystring(stdb, keystring, 0);
477 if (si->shortdescription && *si->shortdescription)
478 tdb_store_bystring(stdb,keystring,string_tdb_data(si->shortdescription),TDB_REPLACE);
480 tdb_store_bystring(stdb,keystring,string_tdb_data(si->description),TDB_REPLACE);
485 /****************************************************************************
486 Create/Open the service control manager tdb. This code a clone of init_group_mapping.
487 ****************************************************************************/
489 BOOL init_svcctl_db(void)
491 const char *vstring = "INFO/version";
496 pstring external_service_list;
497 pstring internal_service_list;
499 const Internal_service_description *isd_ptr;
500 /* svc_list = str_list_make( "etc/init.d/skeleton etc/init.d/syslog", NULL ); */
501 svc_list=(char **)lp_enable_svcctl();
506 pstrcpy(external_service_list,"");
508 service_tdb = tdb_open_log(lock_path("services.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600);
510 DEBUG(0,("Failed to open service db\n"));
511 service_tdb = tdb_open_log(lock_path("services.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
512 if (!service_tdb) return False;
513 DEBUG(0,("Created new services db\n"));
516 if ((-1 == tdb_fetch_uint32(service_tdb, vstring,&vers_id)) || (vers_id != SERVICEDB_VERSION_V1)) {
517 /* wrong version of DB, or db was just created */
518 tdb_traverse(service_tdb, tdb_traverse_delete_fn, NULL);
519 tdb_store_uint32(service_tdb, vstring, SERVICEDB_VERSION_V1);
521 tdb_unlock_bystring(service_tdb, vstring);
523 DEBUG(0,("Initializing services db\n"));
527 /* Get the EXTERNAL services as mentioned by line in smb.conf */
530 DEBUG(10,("Reading information on service %s\n",*svcname));
531 if (get_LSB_data(*svcname,&si));{
532 /* write the information to the TDB */
533 store_service_info(service_tdb,*svcname,&si);
534 /* definitely not efficient to do it this way. */
535 pstrcat(external_service_list,"\"");
536 pstrcat(external_service_list,*svcname);
537 pstrcat(external_service_list,"\" ");
541 pstrcpy(keystring,"EXTERNAL_SERVICES");
542 tdb_lock_bystring(service_tdb, keystring, 0);
543 DEBUG(8,("Storing external service list [%s]\n",external_service_list));
544 tdb_store_bystring(service_tdb,keystring,string_tdb_data(external_service_list),TDB_REPLACE);
545 tdb_unlock_bystring(service_tdb,keystring);
547 /* Get the INTERNAL services */
549 pstrcpy(internal_service_list,"");
552 while (isd_ptr && (isd_ptr->filename)) {
553 DEBUG(10,("Reading information on service %s\n",isd_ptr->filename));
554 if (get_internal_service_data(isd_ptr,&si)){
555 /* write the information to the TDB */
556 store_service_info(service_tdb,(char *)isd_ptr->filename,&si);
557 /* definitely not efficient to do it this way. */
558 pstrcat(internal_service_list,"\"");
559 pstrcat(internal_service_list,isd_ptr->filename);
560 pstrcat(internal_service_list,"\" ");
565 pstrcpy(keystring,"INTERNAL_SERVICES");
566 tdb_lock_bystring(service_tdb, keystring, 0);
567 DEBUG(8,("Storing internal service list [%s]\n",internal_service_list));
568 tdb_store_bystring(service_tdb,keystring,string_tdb_data(internal_service_list),TDB_REPLACE);
569 tdb_unlock_bystring(service_tdb,keystring);