r7563: svcctl patches from Marcin; have cleaned up formating and am checking the...
authorGerald Carter <jerry@samba.org>
Tue, 14 Jun 2005 03:17:31 +0000 (03:17 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:57:14 +0000 (10:57 -0500)
source/include/rpc_svcctl.h
source/rpc_parse/parse_misc.c
source/rpc_parse/parse_svcctl.c
source/rpc_server/srv_svcctl.c
source/rpc_server/srv_svcctl_nt.c
source/smbd/server.c

index 90b90bd24b1e819cd63078ceb3bfb480e4f7bc36..b344804bcfb55ddfaf52fce0bb5f93d4a6fc4402 100644 (file)
@@ -36,6 +36,7 @@
 #define SVCCTL_START_SERVICE_W                 0x13
 #define SVCCTL_GET_DISPLAY_NAME                        0x14
 #define SVCCTL_QUERY_SERVICE_CONFIG2_W         0x27
+#define SVCCTL_QUERY_SERVICE_STATUSEX_W         0x28
 
 /* ANSI versions not implemented currently 
 #define SVCCTL_ENUM_SERVICES_STATUS_A          0x0e
 #define SVCCTL_ACCEPT_HARDWAREPROFILECHANGE    0x00000020
 #define SVCCTL_ACCEPT_POWEREVENT               0x00000040
 
+/* SERVER_STATUS - ControlAccepted */
+#define SVCCTL_SVC_ERROR_IGNORE                 0x00000000
+#define SVCCTL_SVC_ERROR_NORMAL                 0x00000001
+#define SVCCTL_SVC_ERROR_CRITICAL               0x00000002
+#define SVCCTL_SVC_ERROR_SEVERE                 0x00000003
+
+/* QueryServiceConfig2 options */
+#define SERVICE_CONFIG_DESCRIPTION              0x00000001
+#define SERVICE_CONFIG_FAILURE_ACTIONS          0x00000002
+
+
+/* Service Config - values for ServiceType field*/
+
+#define SVCCTL_KERNEL_DRVR                         0x00000001  /* doubtful we'll have these */
+#define SVCCTL_FILE_SYSTEM_DRVR                    0x00000002  
+#define SVCCTL_WIN32_OWN_PROC                      0x00000010
+#define SVCCTL_WIN32_SHARED_PROC                   0x00000020
+#define SVCCTL_WIN32_INTERACTIVE                   0x00000100 
+
+/* Service Config - values for StartType field */
+#define SVCCTL_BOOT_START                          0x00000000
+#define SVCCTL_SYSTEM_START                        0x00000001
+#define SVCCTL_AUTO_START                          0x00000002
+#define SVCCTL_DEMAND_START                        0x00000003
+#define SVCCTL_DISABLED                            0x00000004
+
 /* Service Controls */
 
 #define SVCCTL_CONTROL_STOP                    0x00000001
 #define SVCCTL_CONTROL_PAUSE                   0x00000002
 #define SVCCTL_CONTROL_CONTINUE                        0x00000003
+#define SVCCTL_CONTROL_SHUTDOWN                 0x00000004
+
+#define SVC_HANDLE_IS_SCM        0x0000001
+#define SVC_HANDLE_IS_SERVICE    0x0000002
+
+#define SVC_STATUS_PROCESS_INFO                 0x00000001
 
 /* utility structures for RPCs */
 
@@ -90,6 +123,19 @@ typedef struct {
        uint32 wait_hint;
 } SERVICE_STATUS;
 
+typedef struct {
+       uint32 type;
+       uint32 state;
+       uint32 controls_accepted;
+       uint32 win32_exit_code;
+       uint32 service_exit_code;
+       uint32 check_point;
+       uint32 wait_hint;
+       uint32 process_id;
+       uint32 service_flags;
+} SERVICE_STATUS_PROCESS;
+
+
 typedef struct {
        UNISTR servicename;
        UNISTR displayname;
@@ -108,6 +154,47 @@ typedef struct {
        UNISTR2 *displayname;
 } SERVICE_CONFIG;
 
+typedef struct {
+        UNISTR2 *description;
+} SERVICE_DESCRIPTION;
+
+typedef struct {
+        uint32 type;
+        uint32 delay;
+} SC_ACTION;
+
+typedef struct {
+        uint32 reset_period;
+        UNISTR2 *rebootmsg;
+        UNISTR2 *command;
+        uint32  nActions;
+        SC_ACTION *saActions;
+        UNISTR2 *description;
+} SERVICE_FAILURE_ACTIONS;
+
+
+typedef struct SCM_info_struct {
+       uint32  type;                    /* should be SVC_HANDLE_IS_SCM */
+       pstring target_server_name;      /* name of the server on which the operation is taking place */
+       pstring target_db_name;          /* name of the database that we're opening */
+} SCM_info;
+
+typedef struct Service_info_struct {
+       uint32  type;           /* should be SVC_HANDLE_IS_SERVICE */
+       pstring servicename;    /* the name of the service */
+       pstring servicetype;    /* internal or external */
+       pstring filename;       /* what file name we can find this in, 
+                                  as well as the "index" for what the 
+                                  service name is */
+       pstring provides;
+       pstring dependencies;
+       pstring shouldstart;
+       pstring shouldstop;
+       pstring requiredstart;
+       pstring requiredstop;
+       pstring shortdescription;
+       pstring description;
+} Service_info;
 
 /* rpc structures */
 
@@ -118,6 +205,7 @@ typedef struct {
 } SVCCTL_Q_CLOSE_SERVICE;
 
 typedef struct {
+        POLICY_HND handle;
        WERROR status;
 } SVCCTL_R_CLOSE_SERVICE;
 
@@ -242,5 +330,32 @@ typedef struct {
        WERROR status;
 } SVCCTL_R_QUERY_SERVICE_CONFIG;
 
+typedef struct {
+       POLICY_HND handle;
+        uint32 info_level;
+       uint32 buffer_size;
+} SVCCTL_Q_QUERY_SERVICE_CONFIG2;
+
+typedef struct {
+       UNISTR2 *description;
+        uint32 returned;
+       uint32 needed;
+        uint32 offset;
+       WERROR status;
+} SVCCTL_R_QUERY_SERVICE_CONFIG2;
+
+typedef struct {
+       POLICY_HND handle;
+        uint32 info_level;
+       uint32 buffer_size;
+} SVCCTL_Q_QUERY_SERVICE_STATUSEX;
+
+typedef struct {
+       RPC_BUFFER buffer;
+        uint32 returned;
+       uint32 needed;
+       WERROR status;
+} SVCCTL_R_QUERY_SERVICE_STATUSEX;
+
 #endif /* _RPC_SVCCTL_H */
 
index ccb3e75ac828913f37062e9765bbf83bb4511d4c..2fe448f47d1eeba561e1c3bb321d07d2dd1cb312 100644 (file)
@@ -566,7 +566,7 @@ BOOL smb_io_unistr(const char *desc, UNISTR *uni, prs_struct *ps, int depth)
  Allocate the RPC_DATA_BLOB memory.
 ********************************************************************/
 
-static size_t create_rpc_blob(RPC_DATA_BLOB *str, size_t len)
+size_t create_rpc_blob(RPC_DATA_BLOB *str, size_t len)
 {
        str->buffer = TALLOC_ZERO(get_talloc_ctx(), len);
        if (str->buffer == NULL)
index 1c41a18b99e823aa0f5e4786ce80b8f5bd2b27c9..1f21cb2aab9594cc01d7ed9bc9896925fe7be69b 100644 (file)
@@ -100,6 +100,21 @@ 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++;
+
+       //DEBUG(10, ("_svcctl_io_service_description: descrption is [%s]\n",svcdesc));
+       if (!prs_io_unistr2("", ps, depth, svcdesc))
+               return False;
+
+       return True;
+}
 
 
 /*******************************************************************
@@ -142,6 +157,7 @@ uint32 svcctl_sizeof_enum_services_status( ENUM_SERVICES_STATUS *status )
 
 BOOL svcctl_io_q_close_service(const char *desc, SVCCTL_Q_CLOSE_SERVICE *q_u, prs_struct *ps, int depth)
 {
+        
        if (q_u == NULL)
                return False;
 
@@ -170,7 +186,10 @@ BOOL svcctl_io_r_close_service(const char *desc, SVCCTL_R_CLOSE_SERVICE *r_u, pr
        depth++;
 
        if(!prs_align(ps))
-               return False;
+           return False;
+
+       if(!smb_io_pol_hnd("pol_handle", &r_u->handle, ps, depth))
+          return False; 
 
        if(!prs_werror("status", ps, depth, &r_u->status))
                return False;
@@ -642,6 +661,7 @@ BOOL svcctl_io_r_query_service_config(const char *desc, SVCCTL_R_QUERY_SERVICE_C
        prs_debug(ps, depth, desc, "svcctl_io_r_query_service_config");
        depth++;
 
+
        if(!prs_align(ps))
                return False;
 
@@ -654,6 +674,158 @@ BOOL svcctl_io_r_query_service_config(const char *desc, SVCCTL_R_QUERY_SERVICE_C
        if(!prs_werror("status", ps, depth, &r_u->status))
                return False;
 
+
+       return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL svcctl_io_q_query_service_config2(const char *desc, SVCCTL_Q_QUERY_SERVICE_CONFIG2 *q_u, prs_struct *ps, int depth)
+{
+       if (q_u == NULL)
+               return False;
+
+       prs_debug(ps, depth, desc, "svcctl_io_q_query_service_config2");
+       depth++;
+
+       if(!prs_align(ps))
+               return False;
+
+       if(!smb_io_pol_hnd("service_pol", &q_u->handle, ps, depth))
+               return False;
+
+       if(!prs_uint32("info_level", ps, depth, &q_u->info_level))
+               return False;
+
+       if(!prs_uint32("buffer_size", ps, depth, &q_u->buffer_size))
+               return False;
+
+       return True;
+}
+
+
+/*******************************************************************
+ 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)
+{
+       uint32 offset;
+       char *bp;
+
+       ZERO_STRUCTP(str);
+
+       offset = 4;
+
+       /* 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));
+
+       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);
+               }
+       }
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL svcctl_io_q_query_service_status_ex(const char *desc, SVCCTL_Q_QUERY_SERVICE_STATUSEX *q_u, prs_struct *ps, int depth)
+{
+       if (q_u == NULL)
+               return False;
+
+       prs_debug(ps, depth, desc, "svcctl_io_q_query_service_status_ex");
+       depth++;
+
+       if(!prs_align(ps))
+               return False;
+
+       if(!smb_io_pol_hnd("service_pol", &q_u->handle, ps, depth))
+               return False;
+
+       if(!prs_uint32("info_level", ps, depth, &q_u->info_level))
+               return False;
+
+       if(!prs_uint32("buffer_size", ps, depth, &q_u->buffer_size))
+               return False;
+
+       return True;
+
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL svcctl_io_r_query_service_status_ex(const char *desc, SVCCTL_R_QUERY_SERVICE_STATUSEX *r_u, prs_struct *ps, int depth)
+{
+       if ( !r_u )
+               return False;
+
+       prs_debug(ps, depth, desc, "svcctl_io_r_query_service_status_ex");
+               depth++;
+
+       if (!prs_rpcbuffer("", ps, depth, &r_u->buffer))
+               return False;
+
+       if(!prs_align(ps))
+               return False;
+
+       if(!prs_uint32("needed", ps, depth, &r_u->needed))
+               return False;
+
+       if(!prs_werror("status", ps, depth, &r_u->status))
+               return False;
+
+       return True;
+}
+
+/*******************************************************************
+********************************************************************/
+
+BOOL svcctl_io_r_query_service_config2(const char *desc, SVCCTL_R_QUERY_SERVICE_CONFIG2 *r_u, prs_struct *ps, int depth)
+{
+       if ( !r_u )
+               return False;
+
+       prs_debug(ps, depth, desc, "svcctl_io_r_query_service_config2");
+       depth++;
+
+       if(!prs_align(ps))
+               return False;
+
+       if(!prs_uint32("returned", ps, depth, &r_u->returned))
+               return False;
+
+       if (r_u->returned > 4) {
+               if (!prs_uint32("offset", ps, depth, &r_u->offset))
+                       return False;
+               if(!prs_unistr2(True, "description     ", ps, depth, r_u->description))
+                       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;
+       }
+
+       if (!prs_uint32("needed", ps, depth, &r_u->needed))
+               return False;
+
+       if(!prs_werror("status", ps, depth, &r_u->status))
+               return False;
+
        return True;
 }
 
index 85fb9f9ce3d1846c52a75c25d5a10292dc6a8466..6ba26414d363a0cae3cab341e65a2cb9d828f6ad 100644 (file)
@@ -166,7 +166,29 @@ static BOOL api_svcctl_enum_services_status(pipes_struct *p)
 
        return True;
 }
+/*******************************************************************
+ ********************************************************************/
+
+static BOOL api_svcctl_query_service_status_ex(pipes_struct *p)
+{
+       SVCCTL_Q_QUERY_SERVICE_STATUSEX q_u;
+       SVCCTL_R_QUERY_SERVICE_STATUSEX r_u;
+       prs_struct *data = &p->in_data.data;
+       prs_struct *rdata = &p->out_data.rdata;
+
+       ZERO_STRUCT(q_u);
+       ZERO_STRUCT(r_u);
 
+       if(!svcctl_io_q_query_service_status_ex("", &q_u, data, 0))
+               return False;
+
+       r_u.status = _svcctl_query_service_status_ex(p, &q_u, &r_u);
+
+       if(!svcctl_io_r_query_service_status_ex("", &r_u, rdata, 0))
+               return False;
+
+       return True;
+}
 /*******************************************************************
  ********************************************************************/
 
@@ -263,6 +285,30 @@ static BOOL api_svcctl_query_service_config(pipes_struct *p)
        return True;
 }
 
+/*******************************************************************
+ ********************************************************************/
+
+static BOOL api_svcctl_query_service_config2(pipes_struct *p)
+{
+       SVCCTL_Q_QUERY_SERVICE_CONFIG2 q_u;
+       SVCCTL_R_QUERY_SERVICE_CONFIG2 r_u;
+       prs_struct *data = &p->in_data.data;
+       prs_struct *rdata = &p->out_data.rdata;
+
+       ZERO_STRUCT(q_u);
+       ZERO_STRUCT(r_u);
+
+       if(!svcctl_io_q_query_service_config2("", &q_u, data, 0))
+               return False;
+
+       r_u.status = _svcctl_query_service_config2(p, &q_u, &r_u);
+
+       if(!svcctl_io_r_query_service_config2("", &r_u, rdata, 0))
+               return False;
+
+       return True;
+}
+
 /*******************************************************************
  \PIPE\svcctl commands
  ********************************************************************/
@@ -275,12 +321,15 @@ static struct api_struct api_svcctl_cmds[] =
       { "SVCCTL_GET_DISPLAY_NAME"      , SVCCTL_GET_DISPLAY_NAME      , api_svcctl_get_display_name },
       { "SVCCTL_QUERY_STATUS"          , SVCCTL_QUERY_STATUS          , api_svcctl_query_status },
       { "SVCCTL_QUERY_SERVICE_CONFIG_W", SVCCTL_QUERY_SERVICE_CONFIG_W, api_svcctl_query_service_config },
+      { "SVCCTL_QUERY_SERVICE_CONFIG2_W", SVCCTL_QUERY_SERVICE_CONFIG2_W, api_svcctl_query_service_config2 },
       { "SVCCTL_ENUM_SERVICES_STATUS_W", SVCCTL_ENUM_SERVICES_STATUS_W, api_svcctl_enum_services_status },
       { "SVCCTL_ENUM_DEPENDENT_SERVICES_W", SVCCTL_ENUM_DEPENDENT_SERVICES_W, api_svcctl_enum_dependent_services },
       { "SVCCTL_START_SERVICE_W"       , SVCCTL_START_SERVICE_W       , api_svcctl_start_service },
-      { "SVCCTL_CONTROL_SERVICE"       , SVCCTL_CONTROL_SERVICE       , api_svcctl_control_service }
+      { "SVCCTL_CONTROL_SERVICE"       , SVCCTL_CONTROL_SERVICE       , api_svcctl_control_service },
+      { "SVCCTL_QUERY_SERVICE_STATUSEX_W", SVCCTL_QUERY_SERVICE_STATUSEX_W, api_svcctl_query_service_status_ex }
 };
 
+
 void svcctl_get_pipe_fns( struct api_struct **fns, int *n_fns )
 {
        *fns = api_svcctl_cmds;
index a76e68a312c91f2971f201a8b6db1cf36daf87a0..1feb0f66e4ef394f904363039794cea9ef36055d 100644 (file)
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+/* TODO - Do the OpenService service name matching case-independently, or at least make it an option. */
+
+
 #include "includes.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_RPC_SRV
 
+#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=<list of scripts>                  */
+/* 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 SVCCTL_SCRIPT_DIR  "/svcctl/"
+
 /*
  * sertup the \PIPE\svcctl db API
  */
  
 #define SCVCTL_DATABASE_VERSION_V1 1
+TALLOC_CTX    *svcdb=NULL;
+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}
+};
+
 
 /********************************************************************
+ 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 /* unused static function and static variable*/
+/* parse a LSB init.d type file for things it provides, dependencies, descriptions, etc. */
 
-static TDB_CONTEXT *svcctl_tdb; /* used for share security descriptors */
+/*******************************************************************************
+ Get the INTERNAL services information for the given service name. 
+*******************************************************************************/
 
-static BOOL init_svcctl_db( void )
+static BOOL _svcctl_get_internal_service_data(const Internal_service_description *isd, Service_info *si)
 {
-       static pid_t local_pid;
-       const char *vstring = "INFO/version";
-       /* see if we've already opened the tdb */
+       ZERO_STRUCTP( si );
        
-       if (svcctl_tdb && local_pid == sys_getpid())
-               return True;
+       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);
        
-       /* so open it */        
-       if ( !(svcctl_tdb = tdb_open_log(lock_path("svcctl.tdb"), 0, TDB_DEFAULT, 
-               O_RDWR|O_CREAT, 0600))) 
-       {
-               DEBUG(0,("Failed to open svcctl database %s (%s)\n", 
-                       lock_path("svcctl.tdb"), strerror(errno) ));
+       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 _svcctl_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;
        }
-       local_pid = sys_getpid();
-       /***** BEGIN Check the tdb version ******/
+       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) {
        
-       tdb_lock_bystring(svcctl_tdb, vstring, 0);
+               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;
+}
+
+
+BOOL _svcctl_read_service_tdb_to_si(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;
+}
+
+/*********************************************************************
+ given a service nice name, find the underlying service name
+*********************************************************************/
+
+BOOL  _svcctl_service_nicename_to_servicename(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, ("_svcctl_service_nicename_to_servicename: 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, ("_svcctl_service_nicename_to_servicename: [%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, ("_svcctl_service_nicename_to_servicename: Found service name [%s], name is  [%s]\n",
+               service_nicename,servicename));
+
+       return True;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+BOOL  _svcctl_write_si_to_service_tdb(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"));
        
-       if ( tdb_fetch_int32(svcctl_tdb, vstring) != SCVCTL_DATABASE_VERSION_V1 )
-               tdb_store_int32(svcctl_tdb, vstring, SCVCTL_DATABASE_VERSION_V1);
+       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 (_svcctl_get_LSB_data(*svcname,&si));{
+                       /* write the information to the TDB */
+                       _svcctl_write_si_to_service_tdb(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);
 
-       tdb_unlock_bystring(svcctl_tdb, vstring);
+       /* Get the INTERNAL services */
        
-       /***** END Check the tdb version ******/
+       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 (_svcctl_get_internal_service_data(isd_ptr,&si)){
+                       /* write the information to the TDB */
+                       _svcctl_write_si_to_service_tdb(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;
 }
 
-#endif
+/* Service_info related functions */
+static Service_info *find_service_info_by_hnd(pipes_struct *p, POLICY_HND *handle)
+{
+       Service_info *info = NULL;
 
-/********************************************************************
- TODO
- (a) get and set security descriptors on services
- (b) read and write QUERY_SERVICE_CONFIG structures
- (c) create default secdesc objects for services and SCM
- (d) check access control masks with se_access_check()
- (e) implement SERVICE * for associating with open handles
-********************************************************************/
+       if(!(find_policy_by_hnd(p,handle,(void **)&info)))
+               DEBUG(2,("find_service_info_by_hnd: service not found.\n"));
+
+       return info;
+}
+
+static void free_service_info(void *ptr)
+{
+       Service_info *info = (Service_info *)ptr;
+       memset(info,'0',sizeof(Service_info));
+       SAFE_FREE(info);
+}
+
+/* SCM_info related functions */
+static void free_SCM_info(void *ptr)
+{
+       SCM_info *info = (SCM_info *)ptr;
+       memset(info->target_server_name, '0', sizeof(*(info->target_server_name)));
+       memset(info->target_db_name, '0', sizeof(*(info->target_db_name)));
+       memset(info, 0, sizeof(*(info)));
+       SAFE_FREE(info);
+}
+
+static SCM_info *find_SCManager_info_by_hnd(pipes_struct *p, POLICY_HND *handle)
+{
+       SCM_info *info = NULL;
+    
+       if ( !(find_policy_by_hnd(p,handle,(void **)&info)) ) 
+               DEBUG(2,("svcctl_find_SCManager_info_by_hnd: service not found.\n"));
+
+       return info;
+}
+
+static BOOL _svcctl_open_SCManager_hook(SCM_info *info)
+{
+       return True;
+}
+
+static BOOL _svcctl_close_SCManager_hook(SCM_info *info)
+{
+       return True;
+}
 
 /********************************************************************
 ********************************************************************/
 
 WERROR _svcctl_open_scmanager(pipes_struct *p, SVCCTL_Q_OPEN_SCMANAGER *q_u, SVCCTL_R_OPEN_SCMANAGER *r_u)
 {
-       /* just fake it for now */
-       
-       if ( !create_policy_hnd( p, &r_u->handle, NULL, NULL ) )
-               return WERR_ACCESS_DENIED;
+       /* create the DB of the services that we have  */
        
+       /* associate the information from the service opened in the create_policy_hnd string */
+
+       SCM_info *info = NULL;
+       fstring fhandle_string;
+
+       if(!q_u || !r_u)
+               return WERR_NOMEM;
+    
+       if((info = SMB_MALLOC_P(SCM_info)) == NULL)
+               return WERR_NOMEM;
+    
+       ZERO_STRUCTP(info);
+
+       info->type = SVC_HANDLE_IS_SCM;
+
+       if(q_u->servername != 0)
+               unistr2_to_ascii(info->target_server_name, q_u->servername, sizeof(info->target_server_name));
+       else {
+               /* if servername == NULL, use the local computer */
+               pstrcpy(info->target_server_name, global_myname());
+       }
+       DEBUG(10, ("_svcctl_open_scmanager: Using [%s] as the server name.\n", info->target_server_name));
+
+       if(q_u->database != 0)
+               unistr2_to_ascii(info->target_db_name, q_u->database, sizeof(info->target_db_name));
+       else
+               pstrcpy(info->target_db_name, "ServicesActive");
+
+       if(!create_policy_hnd(p, &(r_u->handle), free_SCM_info, (void *)info))
+               return WERR_NOMEM;
+
+       policy_handle_to_string(&r_u->handle, &fhandle_string);
+       DEBUG(10, ("_svcctl_open_scmanager: Opening [%s] as the target services db, handle [%s]\n", info->target_db_name,fhandle_string));
+
+       if(!(_svcctl_open_SCManager_hook(info))) {
+               /* TODO - should we free the memory that may have been allocated with the policy handle? */
+               return WERR_BADFILE;
+       }
        return WERR_OK;
+
 }
 
 /********************************************************************
@@ -100,29 +614,116 @@ WERROR _svcctl_open_scmanager(pipes_struct *p, SVCCTL_Q_OPEN_SCMANAGER *q_u, SVC
 
 WERROR _svcctl_open_service(pipes_struct *p, SVCCTL_Q_OPEN_SERVICE *q_u, SVCCTL_R_OPEN_SERVICE *r_u)
 {
-       fstring service;
+       pstring service;
+       pstring service_filename;
+       fstring fhandle_string;
+       Service_info *info;
+
+       if(!q_u || !r_u)
+         return WERR_NOMEM;
+    
+       if((info = SMB_MALLOC_P(Service_info)) == NULL)
+         return WERR_NOMEM;
+    
+       ZERO_STRUCTP(info);
+
+       info->type = SVC_HANDLE_IS_SERVICE;
 
        rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0);
        
-       /* can only be called on service name (not displayname) */
+       if (service_tdb == NULL) {
+         DEBUG(1, ("_svcctl_open_service: Cannot open Service [%s], the service database is not open; handle [%s]\n", service,fhandle_string));
+         return WERR_ACCESS_DENIED;
+       }
+       DEBUG(1, ("_svcctl_open_service: Attempting to open Service [%s], \n", service));
+       
+#if 0
+       if ( !_svcctl_service_nicename_to_servicename(service_tdb, service, service_filename, sizeof(pstring)) ) {
+               DEBUG(1, ("_svcctl_open_service: Cannot open Service [%s], the service can't be found\n", service));
+               return WERR_NO_SUCH_SERVICE;
+       }
+#else
+       pstrcpy(service_filename,service);
+#endif
 
+       if (_svcctl_read_service_tdb_to_si(service_tdb,service, info)) 
+               DEBUG(1, ("_svcctl_open_service: Found service [%s], servicename [%s], \n", service, info->servicename));
+       else 
+               return WERR_NO_SUCH_SERVICE;
+       
+#if 0
        if ( !(strequal( service, "NETLOGON") || strequal(service, "Spooler")) )
                return WERR_NO_SUCH_SERVICE;
-
-       if ( !create_policy_hnd( p, &r_u->handle, NULL, NULL ) )
+#endif
+       if ( !create_policy_hnd( p, &(r_u->handle), free_service_info, (void *)info ) )
                return WERR_ACCESS_DENIED;
 
+       policy_handle_to_string(&r_u->handle, &fhandle_string);
+       DEBUG(10, ("_svcctl_open_service: Opening Service [%s], handle [%s]\n", service,fhandle_string));
+
        return WERR_OK;
 }
 
 /********************************************************************
 ********************************************************************/
 
+/* Note that this can be called to close an individual service, ** OR ** the Service Control Manager */
+
 WERROR _svcctl_close_service(pipes_struct *p, SVCCTL_Q_CLOSE_SERVICE *q_u, SVCCTL_R_CLOSE_SERVICE *r_u)
 {
-       if ( !close_policy_hnd( p, &q_u->handle ) )
-               return WERR_BADFID;
-       
+       SCM_info *scminfo;
+       Service_info *svcinfo;
+       POLICY_HND *handle;
+       fstring   fhandle_string;
+       POLICY_HND null_policy_handle;
+
+
+       handle = &(q_u->handle);
+
+       /* a handle is returned  in the close when it's for a service */
+
+       policy_handle_to_string(handle, &fhandle_string);
+       DEBUG(10, ("_svcctl_close_service: Closing handle [%s]\n",fhandle_string));
+
+       ZERO_STRUCT(null_policy_handle);
+
+       policy_handle_to_string(handle, &fhandle_string);
+       DEBUG(10, ("_svcctl_close_service: Closing handle [%s]\n",fhandle_string));
+
+       scminfo = find_SCManager_info_by_hnd(p, handle);
+       if ((NULL != scminfo) && (scminfo->type == SVC_HANDLE_IS_SCM)) {
+               DEBUG(3,("_svcctl_close_service: Closing SERVICE DATABASE [%s]\n", scminfo->target_db_name));
+
+               if(!(_svcctl_close_SCManager_hook(scminfo)))
+                       return WERR_BADFILE;
+
+               if(!(close_policy_hnd(p, handle)))
+               {
+                       /* WERR_NOMEM is probably not the correct error, but until I figure out a better
+                          one it will have to do */
+                       DEBUG(3,("_svcctl_close_service: Can't close SCM \n"));
+                       return WERR_NOMEM;
+               }
+               memcpy(&(r_u->handle),&null_policy_handle, sizeof(POLICY_HND));
+               return WERR_OK;
+       } 
+
+       if ((NULL != scminfo) && (scminfo->type == SVC_HANDLE_IS_SERVICE)) {
+               svcinfo = (Service_info *)scminfo;
+               DEBUG(3,("_svcctl_close_service: Handle is a SERVICE not SCM \n"));
+               DEBUG(3,("_svcctl_close_service: Closing SERVICE [%s]\n", svcinfo->servicename));
+               if(!(close_policy_hnd(p, handle)))
+               {
+                       /* WERR_NOMEM is probably not the correct error, but until I figure out a better
+                          one it will have to do */
+                       DEBUG(3,("_svcctl_close_service: Can't close SERVICE [%s]\n", svcinfo->servicename));
+                       return WERR_NOMEM;
+               }
+       }
+
+       memcpy(&(r_u->handle),&null_policy_handle, sizeof(POLICY_HND));
+
        return WERR_OK;
 }
 
@@ -133,15 +734,34 @@ WERROR _svcctl_get_display_name(pipes_struct *p, SVCCTL_Q_GET_DISPLAY_NAME *q_u,
 {
        fstring service;
        fstring displayname;
+       fstring fhandle_string;
+
+       Service_info *service_info;
+       POLICY_HND *handle;
 
        rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0);
 
-       DEBUG(10,("_svcctl_get_display_name: service name [%s]\n", service));
+       handle = &(q_u->handle);
+       policy_handle_to_string(&q_u->handle, &fhandle_string);
+
+       DEBUG(10, ("_svcctl_get_display_name: Looking for handle [%s]\n",(char *)&fhandle_string));
 
+       service_info = find_service_info_by_hnd(p, handle);
+
+       if (!service_info) {
+               DEBUG(10, ("_svcctl_get_display_name : Can't find the service for the handle\n"));
+               return WERR_ACCESS_DENIED;
+       }
+
+       DEBUG(10, ("_svcctl_get_display_name: Found service [%s], [%s]\n",service_info->servicename,service_info->filename));
+       /* no dependent services...basically a stub function */
+
+#if 0
        if ( !strequal( service, "NETLOGON" ) )
                return WERR_ACCESS_DENIED;
+#endif
+       fstrcpy( displayname, service_info->servicename) ; 
 
-       fstrcpy( displayname, "Net Logon");
        init_svcctl_r_get_display_name( r_u, displayname );
 
        return WERR_OK;
@@ -153,34 +773,266 @@ WERROR _svcctl_get_display_name(pipes_struct *p, SVCCTL_Q_GET_DISPLAY_NAME *q_u,
 WERROR _svcctl_query_status(pipes_struct *p, SVCCTL_Q_QUERY_STATUS *q_u, SVCCTL_R_QUERY_STATUS *r_u)
 {
 
-       r_u->svc_status.type = 0x0110;
+       r_u->svc_status.type = 0x0020;
        r_u->svc_status.state = 0x0004;
        r_u->svc_status.controls_accepted = 0x0005;
 
        return WERR_OK;
 }
 
-/********************************************************************
-********************************************************************/
+/* allocate an array of external services and return them. Null return is okay, make sure &added is also zero! */
 
-WERROR _svcctl_enum_services_status(pipes_struct *p, SVCCTL_Q_ENUM_SERVICES_STATUS *q_u, SVCCTL_R_ENUM_SERVICES_STATUS *r_u)
+int _svcctl_num_external_services(void)
 {
-       ENUM_SERVICES_STATUS *services = NULL;
-       uint32 num_services = 0;
+       int num_services;
+       char **svc_list;
+       pstring keystring, external_services_string;
+       TDB_DATA key_data;
+
+
+       if (!service_tdb) {
+               DEBUG(8,("_svcctl_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,("_svcctl_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 _svcctl_num_external_services is used to "size" the amount of memory allocated, but does little/no work. 
+
+  _svcctl_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 _svcctl_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;
-       size_t buffer_size;
-       WERROR result = WERR_OK;
-               
-       /* num_services = str_list_count( lp_enable_svcctl() ); */
-       num_services = 2;
-       
-       if ( !(services = TALLOC_ARRAY( p->mem_ctx, ENUM_SERVICES_STATUS, num_services )) )
+       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,("_svcctl_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,("_svcctl_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,("_svcctl_enum_external_services: there are no external services\n"));
+               *added = num_services;
+               return WERR_OK;
+       }
+       DEBUG(8,("_svcctl_enum_external_services: there are [%d] external services\n",num_services));
+       si=TALLOC_ARRAY( tcx, Service_info, 1 );
+       if (si == NULL) { 
+               DEBUG(8,("_svcctl_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,("_svcctl_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,("_svcctl_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,("_svcctl_enum_external_services: enumerating %d external services starting at index %d\n", num_services,existing_services));
+
+       while (*svcname) {
+               DEBUG(10,("_svcctl_enum_external_services: Reading information on service %s, index %d\n",*svcname,i));
+               /* _svcctl_get_LSB_data(*svcname,si);  */
+               if (!_svcctl_read_service_tdb_to_si(service_tdb,*svcname, si)) {
+                       DEBUG(1,("_svcctl_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,("_svcctl_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, ("_svcctl_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, ("_svcctl_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,("_svcctl_enum_external_services: Read services %d\n",num_services));
+       *added = num_services;
+
+       return WERR_OK;
+}
+
+int _svcctl_num_internal_services(void)
+{
+       int num_services;
+       char **svc_list;
+       pstring keystring, internal_services_string;
+       TDB_DATA key_data;
+
+       if (!service_tdb) {
+               DEBUG(8,("_svcctl_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,("_svcctl_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
+
+int _svcctl_num_internal_services(void)
+{
+       return 2;
+}
+#endif
+
+/* TODO - for internal services, do similar to external services, except we have to call the right status routine... */
+
+WERROR _svcctl_enum_internal_services(TALLOC_CTX *tcx,ENUM_SERVICES_STATUS **svc_ptr, int existing_services, int *added) 
+{
+       int num_services = 2;
+       int i = 0;
+       ENUM_SERVICES_STATUS *services=NULL;
+
+       if (!svc_ptr || !(*svc_ptr)) 
                return WERR_NOMEM;
-               
-       DEBUG(8,("_svcctl_enum_services_status: Enumerating %d services\n", num_services));
+
+       services = *svc_ptr;
+
+#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,("_svcctl_enum_internal_services: REALLOCing %d services\n", num_services));
+               services = TALLOC_REALLOC_ARRAY(tcx,*svc_ptr,ENUM_SERVICES_STATUS,existing_services+num_services);
+               if (!rsvcs) 
+                       return WERR_NOMEM;
+               *svc_ptr = services;
+       } else {
+               if ( !(services = TALLOC_ARRAY( tcx, ENUM_SERVICES_STATUS, num_services )) )
+                       return WERR_NOMEM;
+       }
+#endif
+
+       if (existing_services > 0) {
+               i += existing_services;
+       }
+       DEBUG(8,("_svcctl_enum_internal_services: Creating %d services, starting index %d\n", num_services,existing_services));
                                
        init_unistr( &services[i].servicename, "Spooler" );
-       init_unistr( &services[i].displayname, "Spooler" );
+       init_unistr( &services[i].displayname, "Print Spooler" );
        
        services[i].status.type               = 0x110;
        services[i].status.controls_accepted  = 0x0;
@@ -195,7 +1047,7 @@ WERROR _svcctl_enum_services_status(pipes_struct *p, SVCCTL_Q_ENUM_SERVICES_STAT
 
        i++;            
        
-       init_unistr( &services[i].servicename, "Netlogon" );
+       init_unistr( &services[i].servicename, "NETLOGON" );
        init_unistr( &services[i].displayname, "Net Logon" );
        
        services[i].status.type               = 0x20;   
@@ -208,30 +1060,90 @@ WERROR _svcctl_enum_services_status(pipes_struct *p, SVCCTL_Q_ENUM_SERVICES_STAT
                services[i].status.state              = SVCCTL_RUNNING;
        else
                services[i].status.state              = SVCCTL_STOPPED;
+
+       *added = num_services;
+
+       return WERR_OK;
+}
+
+WERROR _init_svcdb(void) 
+{
+       if (svcdb) {
+               talloc_destroy(svcdb);
+       }
+       svcdb = talloc_init("services DB");
+
+       return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _svcctl_enum_services_status(pipes_struct *p, SVCCTL_Q_ENUM_SERVICES_STATUS *q_u, SVCCTL_R_ENUM_SERVICES_STATUS *r_u)
+{
+       ENUM_SERVICES_STATUS *services = NULL;
+       uint32 num_int_services = 0;
+       uint32 num_ext_services = 0;
+       int i = 0;
+       size_t buffer_size;
+       WERROR result = WERR_OK;
+       WERROR ext_result = WERR_OK;            
+
+       /* num_services = str_list_count( lp_enable_svcctl() ); */
+
+       /* here's where we'll read the db of external services */
+       /* _svcctl_read_LSB_data(NULL,NULL); */
+       /* init_svcctl_db(); */
        
+       num_int_services = 0;
+
+       num_int_services = _svcctl_num_internal_services();
+
+       num_ext_services =  _svcctl_num_external_services();
+
+       if ( !(services = TALLOC_ARRAY(p->mem_ctx, ENUM_SERVICES_STATUS, num_int_services+num_ext_services )) )
+          return WERR_NOMEM;
+
+        result = _svcctl_enum_internal_services(p->mem_ctx, &services, 0, &num_int_services);
+
+       if (W_ERROR_IS_OK(result)) {
+               DEBUG(8,("_svcctl_enum_services_status: Got %d internal services\n", num_int_services));
+       } 
+
+       ext_result=_svcctl_enum_external_services(p->mem_ctx, &services, num_int_services, &num_ext_services);
+
+       if (W_ERROR_IS_OK(ext_result)) {
+               DEBUG(8,("_svcctl_enum_services_status: Got %d external services\n", num_ext_services));
+       } 
+
+        DEBUG(8,("_svcctl_enum_services_status: total of %d services\n", num_int_services+num_ext_services));
+
        buffer_size = 0;
-       for (i=0; i<num_services; i++ )
-               buffer_size += svcctl_sizeof_enum_services_status( &services[i] );
-               
+        for (i=0;i<num_int_services+num_ext_services;i++) {
+         buffer_size += svcctl_sizeof_enum_services_status(&services[i]);
+       }
+
+       /* */
        buffer_size += buffer_size % 4;
-       
-       if ( buffer_size > q_u->buffer_size ) {
-               num_services = 0;
+       DEBUG(8,("_svcctl_enum_services_status: buffer size passed %d, we need %d\n",
+                q_u->buffer_size, buffer_size));
+
+       if (buffer_size > q_u->buffer_size ) {
+               num_int_services = 0;
+               num_ext_services = 0;
                result = WERR_MORE_DATA;
        }
-               
-       /* we have to set the outgoing buffer size to the same as the 
-          incoming buffer size (even in the case of failure */
 
-       rpcbuf_init( &r_u->buffer, q_u->buffer_size, p->mem_ctx );
-               
+       rpcbuf_init(&r_u->buffer, q_u->buffer_size, p->mem_ctx);
+
        if ( W_ERROR_IS_OK(result) ) {
-               for ( i=0; i<num_services; i++ )
+               for ( i=0; i<num_int_services+num_ext_services; i++ )
                        svcctl_io_enum_services_status( "", &services[i], &r_u->buffer, 0 );
        }
-               
+
        r_u->needed      = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size;
-       r_u->returned    = num_services;
+       r_u->returned    = num_int_services+num_ext_services;
 
        if ( !(r_u->resume = TALLOC_P( p->mem_ctx, uint32 )) )
                return WERR_NOMEM;
@@ -254,7 +1166,75 @@ WERROR _svcctl_start_service(pipes_struct *p, SVCCTL_Q_START_SERVICE *q_u, SVCCT
 
 WERROR _svcctl_control_service(pipes_struct *p, SVCCTL_Q_CONTROL_SERVICE *q_u, SVCCTL_R_CONTROL_SERVICE *r_u)
 {
-       return WERR_ACCESS_DENIED;
+       Service_info *service_info;
+       POLICY_HND   *handle;
+       pstring      command;
+       fstring      fhandle_string;
+       SERVICE_STATUS *service_status;
+       int          ret,fd;
+
+       /* need to find the service name by the handle that is open */
+       handle = &(q_u->handle);
+               policy_handle_to_string(&q_u->handle, &fhandle_string);
+
+       DEBUG(10, ("_svcctl_control_service: Looking for handle [%s]\n",fhandle_string));
+
+       service_info = find_service_info_by_hnd(p, handle);
+
+       if (!service_info) {
+               DEBUG(10, ("_svcctl_control_service : Can't find the service for the handle\n"));
+               return WERR_BADFID; 
+       }
+
+       /* we return a SERVICE_STATUS structure if there's an error. */
+       if ( !(service_status = TALLOC_ARRAY(p->mem_ctx, SERVICE_STATUS, 1 ))  )
+               return WERR_NOMEM;
+
+       DEBUG(10, ("_svcctl_control_service: Found service [%s], [%s]\n",
+               service_info->servicename, service_info->filename));
+
+       /* TODO  - call the service config function here... */
+       memset(command, 0, sizeof(command));
+       if (q_u->control == SVCCTL_CONTROL_STOP) {
+               slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR,
+                       service_info->filename, "stop");
+       }
+
+       if (q_u->control == SVCCTL_CONTROL_PAUSE) {
+               slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR,
+                       service_info->filename, "stop");
+       }
+
+       if (q_u->control == SVCCTL_CONTROL_CONTINUE) {
+               slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR,
+                       service_info->filename, "restart");
+       }
+
+        DEBUG(10, ("_svcctl_control_service: 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, ("_svcctl_enum_external_services: Command returned  [%d]\n", ret));
+
+       /* SET all service_stats bits here...*/
+       if (ret == 0) {
+               service_status->state              = SVCCTL_RUNNING;
+               service_status->controls_accepted  = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP;
+       } else {
+               service_status->state              = SVCCTL_STOPPED;
+               service_status->controls_accepted  = 0;
+       }
+
+       DEBUG(10, ("_svcctl_query_service_config: Should call the commFound service [%s], [%s]\n",service_info->servicename,service_info->filename));
+
+       /* no dependent services...basically a stub function */
+
+       return WERR_OK;
 }
 
 /********************************************************************
@@ -279,17 +1259,256 @@ WERROR _svcctl_enum_dependent_services( pipes_struct *p, SVCCTL_Q_ENUM_DEPENDENT
 /********************************************************************
 ********************************************************************/
 
-WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG *r_u )
+WERROR _svcctl_query_service_status_ex( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_STATUSEX *q_u, SVCCTL_R_QUERY_SERVICE_STATUSEX *r_u )
 {
+        SERVICE_STATUS_PROCESS ssp;
+       fstring fhandle_string;
+       POLICY_HND *handle;
+       Service_info *service_info;
+       pstring     command;
+       int         ret,fd;
+
+       /* 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;
+
+        /* need to find the service name by the handle that is open */
+       handle = &(q_u->handle);
+       policy_handle_to_string(&q_u->handle, &fhandle_string);
+
+       DEBUG(10, ("_svcctl_query_service_status_ex Looking for handle [%s]\n",fhandle_string));
+
+       /* get rid of the easy errors */
+
+       if (q_u->info_level != SVC_STATUS_PROCESS_INFO) {
+               DEBUG(10, ("_svcctl_query_service_status_ex :  Invalid information level specified\n"));
+               return WERR_UNKNOWN_LEVEL; 
+       }
+
+       service_info = find_service_info_by_hnd(p, handle);
+
+       if (!service_info) {
+               DEBUG(10, ("_svcctl_query_service_status_ex : Can't find the service for the handle\n"));
+               return WERR_BADFID; 
+       }
        
+       if (r_u->needed < (sizeof(SERVICE_STATUS_PROCESS)+sizeof(uint32)+sizeof(uint32))) {
+               DEBUG(10, ("_svcctl_query_service_status_ex : buffer size of [%d] is too small.\n",r_u->needed));
+               return WERR_INSUFFICIENT_BUFFER;
+       }
+
+       ZERO_STRUCT(ssp); 
+           
+        if (!strwicmp(service_info->servicetype,"EXTERNAL")) 
+               ssp.type = SVCCTL_WIN32_OWN_PROC;
+       else 
+               ssp.type = SVCCTL_WIN32_SHARED_PROC;
+
+       /* Get the status of the service.. */
+
+       DEBUG(10, ("_svcctl_query_service_status_ex: Found service [%s], [%s]\n",service_info->servicename,service_info->filename));
+       
+        memset(command, 0, sizeof(command));
+
+       slprintf(command, sizeof(command)-1, "%s%s%s %s",
+               dyn_LIBDIR, SVCCTL_SCRIPT_DIR, service_info->filename, "status");
+
+        DEBUG(10, ("_svcctl_query_service_status_ex: 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, ("_svcctl_query_service_status_ex: Command returned  [%d]\n", ret));
+
+       /* SET all service_stats bits here... */
+       if (ret == 0) {
+               ssp.state              = SVCCTL_RUNNING;
+               ssp.controls_accepted  = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP;
+       } else {
+               ssp.state              = SVCCTL_STOPPED;
+               ssp.controls_accepted  = 0;
+       }
+
+       return WERR_OK;
+}
+
+/********************************************************************
+********************************************************************/
+
+WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG *r_u )
+{
+       /* SERVICE_CONFIG *service_config = NULL; */
+       fstring fhandle_string;
+       POLICY_HND *handle;
+       Service_info *service_info;
+       pstring     fullpathinfo;
+        uint32      needed_size;
+
        /* 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;
+
+        /* need to find the service name by the handle that is open */
+       handle = &(q_u->handle);
+       policy_handle_to_string(&q_u->handle, &fhandle_string);
+
+       DEBUG(10, ("_svcctl_query_service_config: Looking for handle [%s]\n",fhandle_string));
+
+       service_info = find_service_info_by_hnd(p, handle);
+
+#if 0
+       if (q_u->buffer_size < sizeof(Service_info)) {
+               /* have to report need more... */
+               /* TODO worst case -- should actualy calc what we need here. */
+               r_u->needed = sizeof(Service_info)+sizeof(pstring)*5; 
+               DEBUG(10, ("_svcctl_query_service_config: NOT ENOUGH BUFFER ALLOCATED FOR RETURN DATA -- provided %d wanted %d\n",
+               q_u->buffer_size,r_u->needed));
+
+               return WERR_INSUFFICIENT_BUFFER;
+       }
+#endif
+       if (!service_info) {
+               DEBUG(10, ("_svcctl_query_service_config : Can't find the service for the handle\n"));
+               return WERR_BADFID; 
+       }
+
+#if 0
+       if ( !(service_config = (SERVICE_CONFIG *)TALLOC_ZERO_P(p->mem_ctx, SERVICE_CONFIG)) )
+               return WERR_NOMEM;
+#endif
+
+       r_u->config.service_type       = SVCCTL_WIN32_OWN_PROC;
+       r_u->config.start_type         = SVCCTL_DEMAND_START;
+       r_u->config.error_control      = SVCCTL_SVC_ERROR_IGNORE;
+       r_u->config.tag_id = 0x00000000;
+
+       /* Init the strings */
+
+       r_u->config.executablepath = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
+       r_u->config.loadordergroup = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
+       r_u->config.dependencies = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
+       r_u->config.startname = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
+       r_u->config.displayname = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
+
+       DEBUG(10, ("_svcctl_query_service_config: Found service [%s], [%s]\n",service_info->servicename,service_info->filename));
+
+       pstrcpy(fullpathinfo,dyn_LIBDIR);
+       pstrcat(fullpathinfo,SVCCTL_SCRIPT_DIR);
+       pstrcat(fullpathinfo,service_info->filename);
+
+       /* Get and calculate the size of the fields. Note that we're still building the fields in the "too-small buffer case"
+          even though we throw it away. */
        
-       /* no dependent services...basically a stub function */
+       DEBUG(10, ("_svcctl_query_service_config: fullpath info [%s]\n",fullpathinfo));
+       init_unistr2(r_u->config.executablepath,fullpathinfo,UNI_STR_TERMINATE);
+       init_unistr2(r_u->config.loadordergroup,"",UNI_STR_TERMINATE);
+       init_unistr2(r_u->config.dependencies,service_info->dependencies,UNI_STR_TERMINATE);
 
-       return WERR_ACCESS_DENIED;
+       /* TODO - if someone really cares, perhaps "LocalSystem" should be changed to something else here... */
+
+       init_unistr2(r_u->config.startname,"LocalSystem",UNI_STR_TERMINATE);
+       init_unistr2(r_u->config.displayname,service_info->servicename,UNI_STR_TERMINATE);
+
+       needed_size = 0x04 + sizeof(SERVICE_CONFIG)+ 2*(
+                     r_u->config.executablepath->uni_str_len +
+                     r_u->config.loadordergroup->uni_str_len + 
+                     r_u->config.dependencies->uni_str_len + 
+                      r_u->config.startname->uni_str_len + 
+                      r_u->config.displayname->uni_str_len);
+       
+               DEBUG(10, ("_svcctl_query_service_config: ****** need to have a buffer of [%d], [%d] for struct \n",needed_size,
+                  sizeof(SERVICE_CONFIG)));
+       DEBUG(10, ("\tsize of executable path : %d\n",r_u->config.executablepath->uni_str_len));
+       DEBUG(10, ("\tsize of loadordergroup  : %d\n", r_u->config.loadordergroup->uni_str_len)); 
+       DEBUG(10, ("\tsize of dependencies    : %d\n", r_u->config.dependencies->uni_str_len)); 
+       DEBUG(10, ("\tsize of startname       : %d\n", r_u->config.startname->uni_str_len));
+       DEBUG(10, ("\tsize of displayname     : %d\n", r_u->config.displayname->uni_str_len));
+
+       if (q_u->buffer_size < needed_size) {
+               /* have to report need more...*/
+               r_u->needed = needed_size;
+                       DEBUG(10, ("_svcctl_query_service_config: ****** zeroing strings for return\n"));
+               memset(&r_u->config,0,sizeof(SERVICE_CONFIG));
+               DEBUG(10, ("_svcctl_query_service_config: Not enouh buffer provided for return -- provided %d wanted %d\n",
+                       q_u->buffer_size,needed_size));
+               return WERR_INSUFFICIENT_BUFFER;
+       }
+
+       return WERR_OK;
 }
 
+/********************************************************************
+********************************************************************/
+
+WERROR _svcctl_query_service_config2( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CONFIG2 *q_u, SVCCTL_R_QUERY_SERVICE_CONFIG2 *r_u )
+{
+       fstring fhandle_string;
+       POLICY_HND *handle;
+       Service_info *service_info;
+        uint32   level, string_buffer_size;
+       /* 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;
+       r_u->description = NULL;               
+       r_u->returned = q_u->buffer_size;
+       r_u->offset = 4;                       
+
+       handle = &(q_u->handle);
+       policy_handle_to_string(&(q_u->handle), &fhandle_string);
+
+       DEBUG(10, ("_svcctl_query_service_config2: Looking for handle [%s]\n",fhandle_string));
+
+       service_info = find_service_info_by_hnd(p, handle);
+
+       if (!service_info) {
+               DEBUG(10, ("_svcctl_query_service_config2 : Can't find the service for the handle\n"));
+               return WERR_BADFID; 
+       }
+       
+       /* 
+          TODO - perhaps move the RPC_DATA_BLOB into the R_QUERY_SERVICE_CONFIG structure, and to the processing in here, vs
+           in the *r_query_config2 marshalling routine...
+       */
+
+       level = q_u->info_level;
+       DEBUG(10, ("_svcctl_query_service_config2: Found service [%s], [%s]\n",service_info->servicename,service_info->filename));
+       DEBUG(10, ("_svcctl_query_service_config2: Looking for level [%x], buffer size is [%x]\n",level,q_u->buffer_size));
+
+       if (SERVICE_CONFIG_DESCRIPTION == level) {
+               if (service_info && service_info->shortdescription) {
+                       /* length of the string, plus the terminator... */
+                       string_buffer_size = strlen(service_info->shortdescription)+1; 
+                       DEBUG(10, ("_svcctl_query_service_config: copying the description [%s] length [%d]\n",
+                       service_info->shortdescription,string_buffer_size));
+           
+                       if (q_u->buffer_size >= ((string_buffer_size)*2+4)) {
+                               r_u->description = TALLOC_ZERO_P(p->mem_ctx,  UNISTR2);
+                               if (!r_u->description) return WERR_NOMEM;
+                                       init_unistr2(r_u->description,service_info->shortdescription,UNI_STR_TERMINATE);
+                       }
+               }
+               else { 
+                       string_buffer_size = 0;
+               }
+               DEBUG(10, ("_svcctl_query_service_config2: buffer needed is [%x], return buffer size is [%x]\n",
+                       string_buffer_size,q_u->buffer_size));
+               if (((string_buffer_size)*2+4) > q_u->buffer_size) {
+                       r_u->needed = (string_buffer_size+1)*2+4;
+                       DEBUG(10, ("_svcctl_query_service_config2: INSUFFICIENT BUFFER\n"));
+                       return WERR_INSUFFICIENT_BUFFER;
+               }
+               DEBUG(10, ("_svcctl_query_service_config2: returning ok, needed is [%x], buffer size is [%x]\n",
+               r_u->needed,q_u->buffer_size));
+
+               return WERR_OK;    
+       } 
+
+       return WERR_ACCESS_DENIED;
+}
index 01515a57266e71355de5fdd443e71cc3e108ab8d..e3d644824056a8859c2bfce4f6bc2a4d0963e3d8 100644 (file)
@@ -887,6 +887,9 @@ void build_options(BOOL screen);
        if (!init_registry())
                exit(1);
 
+       if (!init_svcctl_db())
+                exit(1);
+
        if (!print_backend_init())
                exit(1);