/* * Win32 advapi functions * * Copyright 1995 Sven Verdoolaege * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "windef.h" #include "winbase.h" #include "winsvc.h" #include "winerror.h" #include "winreg.h" #include "wine/unicode.h" #include "heap.h" #include "wine/debug.h" #include "winternl.h" WINE_DEFAULT_DEBUG_CHANNEL(advapi); static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\', 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', 'S','e','r','v','i','c','e','s','\\',0 }; static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M', 'L','O','C','K',0}; static const WCHAR szServiceShmemNameFmtW[] = {'A','D','V','A','P','I','_', 'S','E','B','_','%','s',0}; struct SEB /* service environment block */ { /* resides in service's shared memory object */ DWORD argc; /* variable part of SEB contains service arguments */ }; /****************************************************************************** * SC_HANDLEs */ #define MAX_SERVICE_NAME 256 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE; struct sc_handle; struct sc_manager /* SCM handle */ { HKEY hkey_scm_db; /* handle to services database in the registry */ LONG ref_count; /* handle must remain alive until any related service */ /* handle exists because DeleteService requires it */ }; struct sc_service /* service handle */ { HKEY hkey; /* handle to service entry in the registry (under hkey_scm_db) */ struct sc_handle *sc_manager; /* pointer to SCM handle */ WCHAR name[ MAX_SERVICE_NAME ]; }; struct sc_handle { SC_HANDLE_TYPE htype; union { struct sc_manager manager; struct sc_service service; } u; }; static struct sc_handle* alloc_sc_handle( SC_HANDLE_TYPE htype ) { struct sc_handle *retval; retval = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct sc_handle) ); if( retval != NULL ) { retval->htype = htype; } TRACE("SC_HANDLE type=%d -> %p\n",htype,retval); return retval; } static void free_sc_handle( struct sc_handle* handle ) { if( NULL == handle ) return; switch( handle->htype ) { case SC_HTYPE_MANAGER: { if( InterlockedDecrement( &handle->u.manager.ref_count ) ) /* there are references to this handle */ return; if( handle->u.manager.hkey_scm_db ) RegCloseKey( handle->u.manager.hkey_scm_db ); break; } case SC_HTYPE_SERVICE: { struct sc_handle *h = handle->u.service.sc_manager; if( h ) { /* release SCM handle */ if( 0 == InterlockedDecrement( &h->u.manager.ref_count ) ) { /* it's time to destroy SCM handle */ if( h->u.manager.hkey_scm_db ) RegCloseKey( h->u.manager.hkey_scm_db ); TRACE("SC_HANDLE (SCM) %p type=%d\n",h,h->htype); HeapFree( GetProcessHeap(), 0, h ); } } if( handle->u.service.hkey ) RegCloseKey( handle->u.service.hkey ); break; } } TRACE("SC_HANDLE %p type=%d\n",handle,handle->htype); HeapFree( GetProcessHeap(), 0, handle ); } static void init_service_handle( struct sc_handle* handle, struct sc_handle* sc_manager, HKEY hKey, LPCWSTR lpServiceName ) { /* init sc_service structure */ handle->u.service.hkey = hKey; lstrcpynW( handle->u.service.name, lpServiceName, MAX_SERVICE_NAME ); /* add reference to SCM handle */ InterlockedIncrement( &sc_manager->u.manager.ref_count ); handle->u.service.sc_manager = sc_manager; } /****************************************************************************** * EnumServicesStatusA [ADVAPI32.@] */ BOOL WINAPI EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType, DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned, LPDWORD lpResumeHandle ) { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager, dwServiceType, dwServiceState, lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle); SetLastError (ERROR_ACCESS_DENIED); return FALSE; } /****************************************************************************** * EnumServicesStatusW [ADVAPI32.@] */ BOOL WINAPI EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType, DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned, LPDWORD lpResumeHandle ) { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager, dwServiceType, dwServiceState, lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle); SetLastError (ERROR_ACCESS_DENIED); return FALSE; } /****************************************************************************** * read_scm_lock_data * * helper function for StartServiceCtrlDispatcherA/W * * SCM database is locked by StartService; * open global SCM lock object and read service name */ static BOOL read_scm_lock_data( LPWSTR buffer ) { HANDLE hLock; LPWSTR argptr; hLock = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, szSCMLock ); if( NULL == hLock ) { SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT ); return FALSE; } argptr = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS, 0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) ); if( NULL == argptr ) { CloseHandle( hLock ); return FALSE; } strcpyW( buffer, argptr ); UnmapViewOfFile( argptr ); CloseHandle( hLock ); return TRUE; } /****************************************************************************** * build_arg_vectors * * helper function for StartServiceCtrlDispatcherA/W * * Allocate and initialize array of LPWSTRs to arguments in variable part * of service environment block. * First entry in the array is reserved for service name and not initialized. */ static LPWSTR* build_arg_vectors( struct SEB* seb ) { LPWSTR *ret; LPWSTR argptr; DWORD i; ret = HeapAlloc( GetProcessHeap(), 0, (1 + seb->argc) * sizeof(LPWSTR) ); if( NULL == ret ) return NULL; argptr = (LPWSTR) &seb[1]; for( i = 0; i < seb->argc; i++ ) { ret[ 1 + i ] = argptr; argptr += 1 + strlenW( argptr ); } return ret; } /****************************************************************************** * StartServiceCtrlDispatcherA [ADVAPI32.@] */ BOOL WINAPI StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent ) { LPSERVICE_MAIN_FUNCTIONA fpMain; WCHAR service_name[ MAX_SERVICE_NAME ]; WCHAR object_name[ MAX_PATH ]; HANDLE hServiceShmem = NULL; struct SEB *seb = NULL; DWORD dwNumServiceArgs ; LPWSTR *lpArgVecW = NULL; LPSTR *lpArgVecA; unsigned int i; TRACE("(%p)\n", servent); if( ! read_scm_lock_data( service_name ) ) { /* FIXME: Instead of exiting we fall through and allow service to be executed as ordinary program. This behaviour was specially introduced in the patch submitted against revision 1.45 and so preserved here. */ FIXME("should fail with ERROR_FAILED_SERVICE_CONTROLLER_CONNECT\n"); dwNumServiceArgs = 0; lpArgVecA = NULL; goto run_service; } snprintfW( object_name, MAX_PATH, szServiceShmemNameFmtW, service_name ); hServiceShmem = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, object_name ); if( NULL == hServiceShmem ) return FALSE; seb = MapViewOfFile( hServiceShmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); if( NULL == seb ) { CloseHandle( hServiceShmem ); return FALSE; } lpArgVecW = build_arg_vectors( seb ); if( NULL == lpArgVecW ) { UnmapViewOfFile( seb ); CloseHandle( hServiceShmem ); return FALSE; } lpArgVecW[0] = service_name; dwNumServiceArgs = seb->argc + 1; /* Convert the Unicode arg vectors back to ASCII */ lpArgVecA = (LPSTR*) HeapAlloc( GetProcessHeap(), 0, dwNumServiceArgs*sizeof(LPSTR) ); for(i=0; ilpServiceName) { TRACE("%s at %p)\n", debugstr_a(servent->lpServiceName),servent); fpMain = servent->lpServiceProc; /* try to start the service */ fpMain( dwNumServiceArgs, lpArgVecA); servent++; } if(dwNumServiceArgs) { /* free arg strings */ for(i=0; iargc + 1; /* FIXME: should we blindly start all services? */ while (servent->lpServiceName) { TRACE("%s at %p)\n", debugstr_w(servent->lpServiceName),servent); fpMain = servent->lpServiceProc; /* try to start the service */ fpMain( dwNumServiceArgs, lpServiceArgVectors); servent++; } HeapFree( GetProcessHeap(), 0, lpServiceArgVectors ); UnmapViewOfFile( seb ); CloseHandle( hServiceShmem ); return TRUE; } /****************************************************************************** * LockServiceDatabase [ADVAPI32.@] */ LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager) { HANDLE ret; TRACE("%p\n",hSCManager); ret = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MAX_SERVICE_NAME * sizeof(WCHAR), szSCMLock ); if( ret && GetLastError() == ERROR_ALREADY_EXISTS ) { CloseHandle( ret ); ret = NULL; SetLastError( ERROR_SERVICE_DATABASE_LOCKED ); } TRACE("returning %p\n", ret); return ret; } /****************************************************************************** * UnlockServiceDatabase [ADVAPI32.@] */ BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock) { TRACE("%p\n",ScLock); return CloseHandle( (HANDLE) ScLock ); } /****************************************************************************** * RegisterServiceCtrlHandlerA [ADVAPI32.@] */ SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler ) { FIXME("%s %p\n", lpServiceName, lpfHandler); return 0xcacacafe; } /****************************************************************************** * RegisterServiceCtrlHandlerW [ADVAPI32.@] * * PARAMS * lpServiceName [] * lpfHandler [] */ SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler ) { FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler); return 0xcacacafe; } /****************************************************************************** * SetServiceStatus [ADVAPI32.@] * * PARAMS * hService [] * lpStatus [] */ BOOL WINAPI SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus ) { FIXME("0x%lx %p\n",hService, lpStatus); TRACE("\tType:%lx\n",lpStatus->dwServiceType); TRACE("\tState:%lx\n",lpStatus->dwCurrentState); TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted); TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode); TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode); TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint); TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint); return TRUE; } /****************************************************************************** * OpenSCManagerA [ADVAPI32.@] * * Establish a connection to the service control manager and open its database. * * PARAMS * lpMachineName [I] Pointer to machine name string * lpDatabaseName [I] Pointer to database name string * dwDesiredAccess [I] Type of access * * RETURNS * Success: A Handle to the service control manager database * Failure: NULL */ SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName, DWORD dwDesiredAccess ) { UNICODE_STRING lpMachineNameW; UNICODE_STRING lpDatabaseNameW; SC_HANDLE ret; RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName); RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName); ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess); RtlFreeUnicodeString(&lpDatabaseNameW); RtlFreeUnicodeString(&lpMachineNameW); return ret; } /****************************************************************************** * OpenSCManagerW [ADVAPI32.@] * * See OpenSCManagerA. */ SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName, DWORD dwDesiredAccess ) { struct sc_handle *retval; HKEY hReg; LONG r; TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName), debugstr_w(lpDatabaseName), dwDesiredAccess); /* * FIXME: what is lpDatabaseName? * It should be set to "SERVICES_ACTIVE_DATABASE" according to * docs, but what if it isn't? */ retval = alloc_sc_handle( SC_HTYPE_MANAGER ); if( NULL == retval ) return NULL; retval->u.manager.ref_count = 1; r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg); if (r!=ERROR_SUCCESS) goto error; r = RegOpenKeyExW(hReg, szServiceManagerKey, 0, KEY_ALL_ACCESS, &retval->u.manager.hkey_scm_db); RegCloseKey( hReg ); if (r!=ERROR_SUCCESS) goto error; TRACE("returning %p\n", retval); return (SC_HANDLE) retval; error: free_sc_handle( retval ); return NULL; } /****************************************************************************** * AllocateLocallyUniqueId [ADVAPI32.@] * * PARAMS * lpluid [] */ BOOL WINAPI AllocateLocallyUniqueId( PLUID lpluid ) { lpluid->LowPart = time(NULL); lpluid->HighPart = 0; return TRUE; } /****************************************************************************** * ControlService [ADVAPI32.@] * * Send a control code to a service. * * PARAMS * hService [I] Handle of the service control manager database * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h") * lpServiceStatus [O] Destination for the status of the service, if available * * RETURNS * Success: TRUE. * Failure: FALSE. */ BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl, LPSERVICE_STATUS lpServiceStatus ) { FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus); return TRUE; } /****************************************************************************** * CloseServiceHandle [ADVAPI32.@] * * Close a handle to a service or the service control manager database. * * PARAMS * hSCObject [I] Handle to service or service control manager database * * RETURNS * Success: TRUE * Failure: FALSE */ BOOL WINAPI CloseServiceHandle( SC_HANDLE hSCObject ) { TRACE("(%p)\n", hSCObject); free_sc_handle( (struct sc_handle*) hSCObject ); return TRUE; } /****************************************************************************** * OpenServiceA [ADVAPI32.@] * * Open a handle to a service. * * PARAMS * hSCManager [I] Handle of the service control manager database * lpServiceName [I] Name of the service to open * dwDesiredAccess [I] Access required to the service * * RETURNS * Success: Handle to the service * Failure: NULL */ SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName, DWORD dwDesiredAccess ) { UNICODE_STRING lpServiceNameW; SC_HANDLE ret; RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName); if(lpServiceName) TRACE("Request for service %s\n",lpServiceName); else return FALSE; ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess); RtlFreeUnicodeString(&lpServiceNameW); return ret; } /****************************************************************************** * OpenServiceW [ADVAPI32.@] * * See OpenServiceA. */ SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName, DWORD dwDesiredAccess) { struct sc_handle *hscm = hSCManager; struct sc_handle *retval; HKEY hKey; long r; TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName, dwDesiredAccess); retval = alloc_sc_handle( SC_HTYPE_SERVICE ); if( NULL == retval ) return NULL; r = RegOpenKeyExW( hscm->u.manager.hkey_scm_db, lpServiceName, 0, KEY_ALL_ACCESS, &hKey ); if (r!=ERROR_SUCCESS) { free_sc_handle( retval ); SetLastError( ERROR_SERVICE_DOES_NOT_EXIST ); return NULL; } init_service_handle( retval, hscm, hKey, lpServiceName ); TRACE("returning %p\n",retval); return (SC_HANDLE) retval; } /****************************************************************************** * CreateServiceW [ADVAPI32.@] */ SC_HANDLE WINAPI CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName, LPCWSTR lpDisplayName, DWORD dwDesiredAccess, DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName, LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies, LPCWSTR lpServiceStartName, LPCWSTR lpPassword ) { struct sc_handle *hscm = hSCManager; struct sc_handle *retval; HKEY hKey; LONG r; DWORD dp; static const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 }; static const WCHAR szType[] = {'T','y','p','e',0}; static const WCHAR szStart[] = {'S','t','a','r','t',0}; static const WCHAR szError[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0}; static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0}; static const WCHAR szGroup[] = {'G','r','o','u','p',0}; static const WCHAR szDependencies[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0}; FIXME("%p %s %s\n", hSCManager, debugstr_w(lpServiceName), debugstr_w(lpDisplayName)); retval = alloc_sc_handle( SC_HTYPE_SERVICE ); if( NULL == retval ) return NULL; r = RegCreateKeyExW(hscm->u.manager.hkey_scm_db, lpServiceName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp); if (r!=ERROR_SUCCESS) goto error; init_service_handle( retval, hscm, hKey, lpServiceName ); if (dp != REG_CREATED_NEW_KEY) goto error; if(lpDisplayName) { r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (LPBYTE)lpDisplayName, (strlenW(lpDisplayName)+1)*sizeof(WCHAR) ); if (r!=ERROR_SUCCESS) goto error; } r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) ); if (r!=ERROR_SUCCESS) goto error; r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) ); if (r!=ERROR_SUCCESS) goto error; r = RegSetValueExW(hKey, szError, 0, REG_DWORD, (LPVOID)&dwErrorControl, sizeof (DWORD) ); if (r!=ERROR_SUCCESS) goto error; if(lpBinaryPathName) { r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (LPBYTE)lpBinaryPathName, (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) ); if (r!=ERROR_SUCCESS) goto error; } if(lpLoadOrderGroup) { r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (LPBYTE)lpLoadOrderGroup, (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) ); if (r!=ERROR_SUCCESS) goto error; } if(lpDependencies) { DWORD len = 0; /* determine the length of a double null terminated multi string */ do { len += (strlenW(&lpDependencies[len])+1); } while (lpDependencies[len++]); r = RegSetValueExW(hKey, szDependencies, 0, REG_MULTI_SZ, (LPBYTE)lpDependencies, len ); if (r!=ERROR_SUCCESS) goto error; } if(lpPassword) { FIXME("Don't know how to add a Password for a service.\n"); } if(lpServiceStartName) { FIXME("Don't know how to add a ServiceStartName for a service.\n"); } return (SC_HANDLE) retval; error: free_sc_handle( retval ); return NULL; } static inline LPWSTR SERV_dup( LPCSTR str ) { UINT len; LPWSTR wstr; if( !str ) return NULL; len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 ); wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) ); MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len ); return wstr; } static inline LPWSTR SERV_dupmulti( LPCSTR str ) { UINT len = 0, n = 0; LPWSTR wstr; if( !str ) return NULL; do { len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 ); n += (strlen( &str[n] ) + 1); } while (str[n]); len++; n++; wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) ); MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len ); return wstr; } static inline VOID SERV_free( LPWSTR wstr ) { HeapFree( GetProcessHeap(), 0, wstr ); } /****************************************************************************** * CreateServiceA [ADVAPI32.@] */ SC_HANDLE WINAPI CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName, LPCSTR lpDisplayName, DWORD dwDesiredAccess, DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName, LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies, LPCSTR lpServiceStartName, LPCSTR lpPassword ) { LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW, lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW; SC_HANDLE r; TRACE("%p %s %s\n", hSCManager, debugstr_a(lpServiceName), debugstr_a(lpDisplayName)); lpServiceNameW = SERV_dup( lpServiceName ); lpDisplayNameW = SERV_dup( lpDisplayName ); lpBinaryPathNameW = SERV_dup( lpBinaryPathName ); lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup ); lpDependenciesW = SERV_dupmulti( lpDependencies ); lpServiceStartNameW = SERV_dup( lpServiceStartName ); lpPasswordW = SERV_dup( lpPassword ); r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl, lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId, lpDependenciesW, lpServiceStartNameW, lpPasswordW ); SERV_free( lpServiceNameW ); SERV_free( lpDisplayNameW ); SERV_free( lpBinaryPathNameW ); SERV_free( lpLoadOrderGroupW ); SERV_free( lpDependenciesW ); SERV_free( lpServiceStartNameW ); SERV_free( lpPasswordW ); return r; } /****************************************************************************** * DeleteService [ADVAPI32.@] * * Delete a service from the service control manager database. * * PARAMS * hService [I] Handle of the service to delete * * RETURNS * Success: TRUE * Failure: FALSE */ BOOL WINAPI DeleteService( SC_HANDLE hService ) { struct sc_handle *hsvc = hService; HKEY hKey = hsvc->u.service.hkey; WCHAR valname[MAX_PATH+1]; INT index = 0; LONG rc; DWORD size; size = MAX_PATH+1; /* Clean out the values */ rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0); while (rc == ERROR_SUCCESS) { RegDeleteValueW(hKey,valname); index++; size = MAX_PATH+1; rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0); } RegCloseKey(hKey); hsvc->u.service.hkey = NULL; /* delete the key */ RegDeleteKeyW(hsvc->u.service.sc_manager->u.manager.hkey_scm_db, hsvc->u.service.name); return TRUE; } /****************************************************************************** * StartServiceA [ADVAPI32.@] * * Start a service * * PARAMS * hService [I] Handle of service * dwNumServiceArgs [I] Number of arguments * lpServiceArgVectors [I] Address of array of argument strings * * NOTES * - NT implements this function using an obscure RPC call. * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc * to get things like "%SystemRoot%\\System32\\service.exe" to load. * - This will only work for shared address space. How should the service * args be transferred when address spaces are separated? * - Can only start one service at a time. * - Has no concept of privilege. * * RETURNS * Success: TRUE. * Failure: FALSE */ BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs, LPCSTR *lpServiceArgVectors ) { LPWSTR *lpwstr=NULL; UNICODE_STRING usBuffer; unsigned int i; TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors); if(dwNumServiceArgs) lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0, dwNumServiceArgs*sizeof(LPWSTR) ); else lpwstr = NULL; for(i=0; iu.service.hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size); if (r!=ERROR_SUCCESS) return FALSE; ExpandEnvironmentStringsW(str,path,sizeof(path)); TRACE("Starting service %s\n", debugstr_w(path) ); hLock = LockServiceDatabase( hsvc->u.service.sc_manager ); if( NULL == hLock ) return FALSE; /* * FIXME: start dependent services */ /* pass argv[0] (service name) to the service via global SCM lock object */ shmem_lock = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS, 0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) ); if( NULL == shmem_lock ) { ERR("Couldn't map shared memory\n"); goto done; } strcpyW( shmem_lock, hsvc->u.service.name ); /* create service environment block */ size = sizeof(struct SEB); for( i = 0; i < dwNumServiceArgs; i++ ) size += sizeof(WCHAR) * (1 + strlenW( lpServiceArgVectors[ i ] )); snprintfW( str, MAX_PATH, szServiceShmemNameFmtW, hsvc->u.service.name ); hServiceShmem = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, str ); if( NULL == hServiceShmem ) { ERR("Couldn't create shared memory object\n"); goto done; } if( GetLastError() == ERROR_ALREADY_EXISTS ) { SetLastError( ERROR_SERVICE_ALREADY_RUNNING ); goto done; } seb = MapViewOfFile( hServiceShmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); if( NULL == seb ) { ERR("Couldn't map shared memory\n"); goto done; } /* copy service args to SEB */ seb->argc = dwNumServiceArgs; argptr = (LPWSTR) &seb[1]; for( i = 0; i < dwNumServiceArgs; i++ ) { strcpyW( argptr, lpServiceArgVectors[ i ] ); argptr += 1 + strlenW( argptr ); } wait = CreateSemaphoreW(NULL,0,1,_WaitServiceStartW); if (!wait) { ERR("Couldn't create wait semaphore\n"); goto done; } ZeroMemory(&startupinfo,sizeof(STARTUPINFOW)); startupinfo.cb = sizeof(STARTUPINFOW); r = CreateProcessW(NULL, path, NULL, /* process security attribs */ NULL, /* thread security attribs */ FALSE, /* inherit handles */ 0, /* creation flags */ NULL, /* environment */ NULL, /* current directory */ &startupinfo, /* startup info */ &procinfo); /* process info */ if(r == FALSE) { ERR("Couldn't start process\n"); goto done; } CloseHandle( procinfo.hThread ); /* docs for StartServiceCtrlDispatcher say this should be 30 sec */ r = WaitForSingleObject(wait,30000); if( WAIT_FAILED == r ) { CloseHandle( procinfo.hProcess ); goto done; } /* allright */ CloseHandle( procinfo.hProcess ); ret = TRUE; done: if( wait ) CloseHandle( wait ); if( seb != NULL ) UnmapViewOfFile( seb ); if( hServiceShmem != NULL ) CloseHandle( hServiceShmem ); if( shmem_lock != NULL ) UnmapViewOfFile( shmem_lock ); UnlockServiceDatabase( hLock ); return ret; } /****************************************************************************** * QueryServiceStatus [ADVAPI32.@] * * PARAMS * hService [] * lpservicestatus [] * */ BOOL WINAPI QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus ) { struct sc_handle *hsvc = hService; LONG r; DWORD type, val, size; FIXME("(%p,%p) partial\n",hService,lpservicestatus); /* read the service type from the registry */ size = sizeof(val); r = RegQueryValueExA(hsvc->u.service.hkey, "Type", NULL, &type, (LPBYTE)&val, &size); if(type!=REG_DWORD) { ERR("invalid Type\n"); return FALSE; } lpservicestatus->dwServiceType = val; /* FIXME: how are these determined or read from the registry? */ /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */; lpservicestatus->dwCurrentState = 1; lpservicestatus->dwControlsAccepted = 0; lpservicestatus->dwWin32ExitCode = NO_ERROR; lpservicestatus->dwServiceSpecificExitCode = 0; lpservicestatus->dwCheckPoint = 0; lpservicestatus->dwWaitHint = 0; return TRUE; } /****************************************************************************** * QueryServiceStatusEx [ADVAPI32.@] * * Get information about a service. * * PARAMS * hService [I] Handle to service to get information about * InfoLevel [I] Level of information to get * lpBuffer [O] Destination for requested information * cbBufSize [I] Size of lpBuffer in bytes * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small * * RETURNS * Success: TRUE * FAILURE: FALSE */ BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel, LPBYTE lpBuffer, DWORD cbBufSize, LPDWORD pcbBytesNeeded) { FIXME("stub\n"); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } /****************************************************************************** * QueryServiceConfigA [ADVAPI32.@] */ BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA lpServiceConfig, DWORD cbBufSize, LPDWORD pcbBytesNeeded) { static const CHAR szDisplayName[] = "DisplayName"; static const CHAR szType[] = "Type"; static const CHAR szStart[] = "Start"; static const CHAR szError[] = "ErrorControl"; static const CHAR szImagePath[] = "ImagePath"; static const CHAR szGroup[] = "Group"; static const CHAR szDependencies[] = "Dependencies"; HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey; CHAR str_buffer[ MAX_PATH ]; LONG r; DWORD type, val, sz, total, n; LPBYTE p; TRACE("%p %p %ld %p\n", hService, lpServiceConfig, cbBufSize, pcbBytesNeeded); /* calculate the size required first */ total = sizeof (QUERY_SERVICE_CONFIGA); sz = sizeof(str_buffer); r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz ); if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) ) { sz = ExpandEnvironmentStringsA(str_buffer,NULL,0); if( 0 == sz ) return FALSE; total += sz; } else { /* FIXME: set last error */ return FALSE; } sz = 0; r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz ); if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) ) total += sz; sz = 0; r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz ); if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) ) total += sz; sz = 0; r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz ); if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) ) total += sz; sz = 0; r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz ); if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) ) total += sz; /* if there's not enough memory, return an error */ if( total > *pcbBytesNeeded ) { *pcbBytesNeeded = total; SetLastError( ERROR_INSUFFICIENT_BUFFER ); return FALSE; } *pcbBytesNeeded = total; ZeroMemory( lpServiceConfig, total ); sz = sizeof val; r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz ); if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) ) lpServiceConfig->dwServiceType = val; sz = sizeof val; r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz ); if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) ) lpServiceConfig->dwStartType = val; sz = sizeof val; r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz ); if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) ) lpServiceConfig->dwErrorControl = val; /* now do the strings */ p = (LPBYTE) &lpServiceConfig[1]; n = total - sizeof (QUERY_SERVICE_CONFIGA); sz = sizeof(str_buffer); r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz ); if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) ) { sz = ExpandEnvironmentStringsA(str_buffer, p, n); if( 0 == sz || sz > n ) return FALSE; lpServiceConfig->lpBinaryPathName = (LPSTR) p; p += sz; n -= sz; } else { /* FIXME: set last error */ return FALSE; } sz = n; r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz ); if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) ) { lpServiceConfig->lpLoadOrderGroup = (LPSTR) p; p += sz; n -= sz; } sz = n; r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz ); if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) ) { lpServiceConfig->lpDependencies = (LPSTR) p; p += sz; n -= sz; } if( n < 0 ) ERR("Buffer overflow!\n"); TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName ); TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup ); return TRUE; } /****************************************************************************** * QueryServiceConfigW [ADVAPI32.@] */ BOOL WINAPI QueryServiceConfigW( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGW lpServiceConfig, DWORD cbBufSize, LPDWORD pcbBytesNeeded) { static const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 }; static const WCHAR szType[] = {'T','y','p','e',0}; static const WCHAR szStart[] = {'S','t','a','r','t',0}; static const WCHAR szError[] = { 'E','r','r','o','r','C','o','n','t','r','o','l', 0}; static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0}; static const WCHAR szGroup[] = {'G','r','o','u','p',0}; static const WCHAR szDependencies[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0}; HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey; WCHAR str_buffer[ MAX_PATH ]; LONG r; DWORD type, val, sz, total, n; LPBYTE p; TRACE("%p %p %ld %p\n", hService, lpServiceConfig, cbBufSize, pcbBytesNeeded); /* calculate the size required first */ total = sizeof (QUERY_SERVICE_CONFIGW); sz = sizeof(str_buffer); r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz ); if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) ) { sz = ExpandEnvironmentStringsW(str_buffer,NULL,0); if( 0 == sz ) return FALSE; total += sizeof(WCHAR) * sz; } else { /* FIXME: set last error */ return FALSE; } sz = 0; r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz ); if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) ) total += sz; sz = 0; r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz ); if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) ) total += sz; sz = 0; r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz ); if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) ) total += sz; sz = 0; r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz ); if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) ) total += sz; /* if there's not enough memory, return an error */ if( total > *pcbBytesNeeded ) { *pcbBytesNeeded = total; SetLastError( ERROR_INSUFFICIENT_BUFFER ); return FALSE; } *pcbBytesNeeded = total; ZeroMemory( lpServiceConfig, total ); sz = sizeof val; r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz ); if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) ) lpServiceConfig->dwServiceType = val; sz = sizeof val; r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz ); if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) ) lpServiceConfig->dwStartType = val; sz = sizeof val; r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz ); if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) ) lpServiceConfig->dwErrorControl = val; /* now do the strings */ p = (LPBYTE) &lpServiceConfig[1]; n = total - sizeof (QUERY_SERVICE_CONFIGW); sz = sizeof(str_buffer); r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz ); if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) ) { sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n); sz *= sizeof(WCHAR); if( 0 == sz || sz > n ) return FALSE; lpServiceConfig->lpBinaryPathName = (LPWSTR) p; p += sz; n -= sz; } else { /* FIXME: set last error */ return FALSE; } sz = n; r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz ); if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) ) { lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p; p += sz; n -= sz; } sz = n; r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz ); if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) ) { lpServiceConfig->lpDependencies = (LPWSTR) p; p += sz; n -= sz; } if( n < 0 ) ERR("Buffer overflow!\n"); TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) ); TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) ); return TRUE; } /****************************************************************************** * ChangeServiceConfigW [ADVAPI32.@] */ BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName, LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies, LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName) { FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n", hService, dwServiceType, dwStartType, dwErrorControl, debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup), lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName), debugstr_w(lpPassword), debugstr_w(lpDisplayName) ); return TRUE; } /****************************************************************************** * ChangeServiceConfigA [ADVAPI32.@] */ BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName, LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies, LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName) { FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n", hService, dwServiceType, dwStartType, dwErrorControl, debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup), lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName), debugstr_a(lpPassword), debugstr_a(lpDisplayName) ); return TRUE; } /****************************************************************************** * ChangeServiceConfig2A [ADVAPI32.@] */ BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, LPVOID lpInfo) { FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo); return TRUE; } /****************************************************************************** * ChangeServiceConfig2W [ADVAPI32.@] */ BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, LPVOID lpInfo) { HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey; if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION) { static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0}; LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo; if (sd->lpDescription) { TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription)); if (sd->lpDescription[0] == 0) RegDeleteValueW(hKey,szDescription); else RegSetValueExW(hKey, szDescription, 0, REG_SZ, (LPVOID)sd->lpDescription, sizeof(WCHAR)*(strlenW(sd->lpDescription)+1)); } } else FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo); return TRUE; } /****************************************************************************** * QueryServiceObjectSecurity [ADVAPI32.@] */ BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService, SECURITY_INFORMATION dwSecurityInformation, PSECURITY_DESCRIPTOR lpSecurityDescriptor, DWORD cbBufSize, LPDWORD pcbBytesNeeded) { FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation, lpSecurityDescriptor, cbBufSize, pcbBytesNeeded); return ERROR_CALL_NOT_IMPLEMENTED; }