service.c 67.5 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 * Win32 advapi functions
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
4
 * Copyright 1995 Sven Verdoolaege
5
 * Copyright 2005 Mike McCormack
6
 * Copyright 2007 Rolf Kalbermatter
7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * 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
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
21 22
 */

23 24 25
#include "config.h"
#include "wine/port.h"

26
#include <stdarg.h>
27
#include <string.h>
28
#include <time.h>
29
#include <assert.h>
30

31
#include "windef.h"
32
#include "winbase.h"
33
#include "winsvc.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
34
#include "winerror.h"
35
#include "winreg.h"
36
#include "wine/unicode.h"
37
#include "wine/debug.h"
38
#include "winternl.h"
39 40
#include "lmcons.h"
#include "lmserver.h"
41

42 43
#include "svcctl.h"

44 45
#include "wine/exception.h"

46
WINE_DEFAULT_DEBUG_CHANNEL(service);
47

48 49
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','\\',
50
      'S','e','r','v','i','c','e','s',0 };
51

52 53 54 55 56 57 58 59 60 61
void  __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len)
{
    return HeapAlloc(GetProcessHeap(), 0, len);
}

void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
{
    HeapFree(GetProcessHeap(), 0, ptr);
}

62 63 64 65 66 67 68
static const GENERIC_MAPPING scm_generic = {
    (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
    (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
    (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
    SC_MANAGER_ALL_ACCESS
};

69 70 71 72 73 74 75
static const GENERIC_MAPPING svc_generic = {
    (STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS),
    (STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG),
    (STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL),
    SERVICE_ALL_ACCESS
};

76 77
typedef struct service_data_t
{
78
    LPHANDLER_FUNCTION_EX handler;
79
    LPVOID context;
80
    HANDLE thread;
81
    SC_HANDLE handle;
82
    BOOL unicode : 1;
83 84 85 86 87 88 89 90 91 92 93 94 95 96
    union {
        LPSERVICE_MAIN_FUNCTIONA a;
        LPSERVICE_MAIN_FUNCTIONW w;
    } proc;
    LPWSTR args;
    WCHAR name[1];
} service_data;

static CRITICAL_SECTION service_cs;
static CRITICAL_SECTION_DEBUG service_cs_debug =
{
    0, 0, &service_cs,
    { &service_cs_debug.ProcessLocksList, 
      &service_cs_debug.ProcessLocksList },
97
      0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
98
};
99
static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
100

101 102
static service_data **services;
static unsigned int nb_services;
103
static HANDLE service_event;
104

105
extern HANDLE CDECL __wine_make_process_system(void);
106

107 108 109 110 111 112 113 114 115
/******************************************************************************
 * SC_HANDLEs
 */

#define MAX_SERVICE_NAME 256

typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;

struct sc_handle;
116
typedef VOID (*sc_handle_destructor)(struct sc_handle *);
117

118
struct sc_handle
119
{
120 121 122
    SC_HANDLE_TYPE htype;
    DWORD ref_count;
    sc_handle_destructor destroy;
123
    SC_RPC_HANDLE server_handle;     /* server-side handle */
124 125
};

126
struct sc_manager       /* service control manager handle */
127
{
128 129
    struct sc_handle hdr;
    HKEY   hkey;   /* handle to services database in the registry */
130
    DWORD  dwAccess;
131 132
};

133
struct sc_service       /* service handle */
134
{
135 136
    struct sc_handle hdr;
    HKEY   hkey;          /* handle to service entry in the registry (under hkey) */
137
    DWORD  dwAccess;
138 139
    struct sc_manager *scm;  /* pointer to SCM handle */
    WCHAR  name[1];
140 141
};

142 143
static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
                             sc_handle_destructor destroy)
144
{
145
    struct sc_handle *hdr;
146

147 148
    hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
    if (hdr)
149
    {
150 151 152
        hdr->htype = htype;
        hdr->ref_count = 1;
        hdr->destroy = destroy;
153
    }
154 155
    TRACE("sc_handle type=%d -> %p\n", htype, hdr);
    return hdr;
156 157
}

158
static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
159
{
160
    struct sc_handle *hdr = (struct sc_handle *) handle;
161

162 163 164 165 166 167
    if (!hdr)
        return NULL;
    if (hdr->htype != htype)
        return NULL;
    return hdr;
}
168

169 170 171 172 173 174 175 176 177
static void sc_handle_free(struct sc_handle* hdr)
{
    if (!hdr)
        return;
    if (--hdr->ref_count)
        return;
    hdr->destroy(hdr);
    HeapFree(GetProcessHeap(), 0, hdr);
}
178

179 180 181
static void sc_handle_destroy_manager(struct sc_handle *handle)
{
    struct sc_manager *mgr = (struct sc_manager*) handle;
182

183 184 185
    TRACE("destroying SC Manager %p\n", mgr);
    if (mgr->hkey)
        RegCloseKey(mgr->hkey);
186 187
}

188
static void sc_handle_destroy_service(struct sc_handle *handle)
189
{
190 191 192 193 194 195 196 197
    struct sc_service *svc = (struct sc_service*) handle;
    
    TRACE("destroying service %p\n", svc);
    if (svc->hkey)
        RegCloseKey(svc->hkey);
    svc->hkey = NULL;
    sc_handle_free(&svc->scm->hdr);
    svc->scm = NULL;
198
}
199

200
/******************************************************************************
201 202 203
 * String management functions (same behaviour as strdup)
 * NOTE: the caller of those functions is responsible for calling HeapFree
 * in order to release the memory allocated by those functions.
204
 */
205 206 207 208 209 210 211 212 213 214 215 216 217
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;
}

218
static inline LPWSTR SERV_dupmulti(LPCSTR str)
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
{
    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;
}

237 238 239 240 241 242 243 244 245 246 247 248
static inline DWORD multisz_cb(LPCWSTR wmultisz)
{
    const WCHAR *wptr = wmultisz;

    if (wmultisz == NULL)
        return 0;

    while (*wptr)
        wptr += lstrlenW(wptr)+1;
    return (wptr - wmultisz + 1)*sizeof(WCHAR);
}

249
/******************************************************************************
250
 * RPC connection with services.exe
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
 */

handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
{
    WCHAR transport[] = SVCCTL_TRANSPORT;
    WCHAR endpoint[] = SVCCTL_ENDPOINT;
    RPC_WSTR binding_str;
    RPC_STATUS status;
    handle_t rpc_handle;

    status = RpcStringBindingComposeW(NULL, transport, (RPC_WSTR)MachineName, endpoint, NULL, &binding_str);
    if (status != RPC_S_OK)
    {
        ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
        return NULL;
    }

    status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
    RpcStringFreeW(&binding_str);

    if (status != RPC_S_OK)
    {
        ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
        return NULL;
    }

    return rpc_handle;
}

void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
{
    RpcBindingFree(&h);
}

285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
{
    return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
}

static DWORD map_exception_code(DWORD exception_code)
{
    switch (exception_code)
    {
    case RPC_X_NULL_REF_POINTER:
    case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
    case RPC_X_BYTE_COUNT_TOO_SMALL:
        return ERROR_INVALID_PARAMETER;
    default:
        return exception_code;
    }
}

303
/******************************************************************************
304
 * Service IPC functions
305
 */
306
static LPWSTR service_get_pipe_name(void)
307
{
308 309 310 311 312 313
    static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
        'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
    static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
        'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
        'C','o','n','t','r','o','l','\\',
        'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
314 315
    LPWSTR name;
    DWORD len;
316 317 318 319
    HKEY service_current_key;
    DWORD service_current;
    LONG ret;
    DWORD type;
320

321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
    ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
        KEY_QUERY_VALUE, &service_current_key);
    if (ret != ERROR_SUCCESS)
        return NULL;
    len = sizeof(service_current);
    ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
        (BYTE *)&service_current, &len);
    RegCloseKey(service_current_key);
    if (ret != ERROR_SUCCESS || type != REG_DWORD)
        return NULL;
    len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
    name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
    if (!name)
        return NULL;
    snprintfW(name, len, format, service_current);
336 337 338
    return name;
}

339
static HANDLE service_open_pipe(void)
340
{
341
    LPWSTR szPipe = service_get_pipe_name();
342 343 344 345 346 347 348 349 350 351
    HANDLE handle = INVALID_HANDLE_VALUE;

    do {
        handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
                         0, NULL, OPEN_ALWAYS, 0, NULL);
        if (handle != INVALID_HANDLE_VALUE)
            break;
        if (GetLastError() != ERROR_PIPE_BUSY)
            break;
    } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
352
    HeapFree(GetProcessHeap(), 0, szPipe);
353 354 355 356

    return handle;
}

357 358 359 360 361 362 363 364 365 366 367
static service_data *find_service_by_name( const WCHAR *name )
{
    unsigned int i;

    if (nb_services == 1)  /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
        return services[0];
    for (i = 0; i < nb_services; i++)
        if (!strcmpiW( name, services[i]->name )) return services[i];
    return NULL;
}

368
/******************************************************************************
369
 * service_thread
370
 *
371
 * Call into the main service routine provided by StartServiceCtrlDispatcher.
372
 */
373
static DWORD WINAPI service_thread(LPVOID arg)
374
{
375 376 377
    service_data *info = arg;
    LPWSTR str = info->args;
    DWORD argc = 0, len = 0;
378

379 380 381 382 383 384 385
    TRACE("%p\n", arg);

    while (str[len])
    {
        len += strlenW(&str[len]) + 1;
        argc++;
    }
386
    len++;
387

388 389 390
    if (info->unicode)
    {
        LPWSTR *argv, p;
391

392 393 394 395 396 397 398 399
        argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
        for (argc=0, p=str; *p; p += strlenW(p) + 1)
            argv[argc++] = p;
        argv[argc] = NULL;

        info->proc.w(argc, argv);
        HeapFree(GetProcessHeap(), 0, argv);
    }
400
    else
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
    {
        LPSTR strA, *argv, p;
        DWORD lenA;
        
        lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
        strA = HeapAlloc(GetProcessHeap(), 0, lenA);
        WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);

        argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
        for (argc=0, p=strA; *p; p += strlen(p) + 1)
            argv[argc++] = p;
        argv[argc] = NULL;

        info->proc.a(argc, argv);
        HeapFree(GetProcessHeap(), 0, argv);
        HeapFree(GetProcessHeap(), 0, strA);
    }
    return 0;
419 420
}

421
/******************************************************************************
422
 * service_handle_start
423
 */
424
static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
425
{
426
    TRACE("%s argsize %u\n", debugstr_w(service->name), count);
427 428 429

    if (service->thread)
    {
430
        WARN("service is not stopped\n");
431
        return ERROR_SERVICE_ALREADY_RUNNING;
432 433
    }

434
    HeapFree(GetProcessHeap(), 0, service->args);
435 436
    service->args = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
    memcpy( service->args, data, count * sizeof(WCHAR) );
437 438
    service->thread = CreateThread( NULL, 0, service_thread,
                                    service, 0, NULL );
439
    SetEvent( service_event );  /* notify the main loop */
440
    return 0;
441 442
}

443
/******************************************************************************
444
 * service_handle_control
445
 */
446
static DWORD service_handle_control(service_data *service, DWORD dwControl)
447
{
448 449 450
    DWORD ret = ERROR_INVALID_SERVICE_CONTROL;

    TRACE("%s control %u\n", debugstr_w(service->name), dwControl);
451

452 453
    if (service->handler)
        ret = service->handler(dwControl, 0, NULL, service->context);
454
    return ret;
455 456 457 458 459 460 461
}

/******************************************************************************
 * service_control_dispatcher
 */
static DWORD WINAPI service_control_dispatcher(LPVOID arg)
{
462
    SC_HANDLE manager;
463
    HANDLE pipe;
464

465 466 467 468 469
    if (!(manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
    {
        ERR("failed to open service manager error %u\n", GetLastError());
        return 0;
    }
470

471
    pipe = service_open_pipe();
472 473

    if (pipe==INVALID_HANDLE_VALUE)
474
    {
475
        ERR("failed to create control pipe error = %d\n", GetLastError());
476 477
        return 0;
    }
478

479
    /* dispatcher loop */
480
    while (1)
481
    {
482 483 484
        service_data *service;
        service_start_info info;
        WCHAR *data = NULL;
485
        BOOL r;
486
        DWORD data_size = 0, count, result;
487

488
        r = ReadFile( pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
489
        if (!r)
490
        {
491 492 493 494
            if (GetLastError() != ERROR_BROKEN_PIPE)
                ERR( "pipe read failed error %u\n", GetLastError() );
            break;
        }
495
        if (count != FIELD_OFFSET(service_start_info,data))
496 497
        {
            ERR( "partial pipe read %u\n", count );
498 499
            break;
        }
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
        if (count < info.total_size)
        {
            data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
            data = HeapAlloc( GetProcessHeap(), 0, data_size );
            r = ReadFile( pipe, data, data_size, &count, NULL );
            if (!r)
            {
                if (GetLastError() != ERROR_BROKEN_PIPE)
                    ERR( "pipe read failed error %u\n", GetLastError() );
                break;
            }
            if (count != data_size)
            {
                ERR( "partial pipe read %u/%u\n", count, data_size );
                break;
            }
        }

        /* find the service */

        if (!(service = find_service_by_name( data )))
        {
            FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(data));
            result = ERROR_INVALID_PARAMETER;
            goto done;
        }

        TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(data) );
528

529
        /* handle the request */
530
        switch (info.cmd)
531
        {
532
        case WINESERV_STARTINFO:
533 534 535 536 537 538 539
            if (!service->handle)
            {
                if (!(service->handle = OpenServiceW( manager, data, SERVICE_SET_STATUS )))
                    FIXME( "failed to open service %s\n", debugstr_w(data) );
            }
            result = service_handle_start(service, data + info.name_size,
                                          data_size / sizeof(WCHAR) - info.name_size );
540 541
            break;
        case WINESERV_SENDCONTROL:
542
            result = service_handle_control(service, info.control);
543 544
            break;
        default:
545 546 547
            ERR("received invalid command %u\n", info.cmd);
            result = ERROR_INVALID_PARAMETER;
            break;
548
        }
549 550 551 552

    done:
        WriteFile(pipe, &result, sizeof(result), &count, NULL);
        HeapFree( GetProcessHeap(), 0, data );
553 554
    }

555
    CloseHandle(pipe);
556
    CloseServiceHandle( manager );
557
    return 1;
558 559
}

560
/******************************************************************************
561
 * service_run_main_thread
Alexandre Julliard's avatar
Alexandre Julliard committed
562
 */
563
static BOOL service_run_main_thread(void)
564
{
565 566 567
    DWORD i, n, ret;
    HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
    UINT wait_services[MAXIMUM_WAIT_OBJECTS];
568

569
    service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
570

571
    /* FIXME: service_control_dispatcher should be merged into the main thread */
572
    wait_handles[0] = __wine_make_process_system();
573 574
    wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, NULL, 0, NULL );
    wait_handles[2] = service_event;
575

576
    TRACE("Starting %d services running as process %d\n",
577
          nb_services, GetCurrentProcessId());
578 579

    /* wait for all the threads to pack up and exit */
580
    for (;;)
581
    {
582
        EnterCriticalSection( &service_cs );
583
        for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
584 585 586 587 588 589 590 591
        {
            if (!services[i]->thread) continue;
            wait_services[n] = i;
            wait_handles[n++] = services[i]->thread;
        }
        LeaveCriticalSection( &service_cs );

        ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
592 593 594 595 596 597
        if (!ret)  /* system process event */
        {
            TRACE( "last user process exited, shutting down\n" );
            /* FIXME: we should maybe send a shutdown control to running services */
            ExitProcess(0);
        }
598
        else if (ret == 1)
599 600 601 602 603 604
        {
            TRACE( "control dispatcher exited, shutting down\n" );
            /* FIXME: we should maybe send a shutdown control to running services */
            ExitProcess(0);
        }
        else if (ret == 2)
605
        {
606
            continue;  /* rebuild the list */
607
        }
608 609 610 611
        else if (ret < n)
        {
            services[wait_services[ret]]->thread = 0;
            CloseHandle( wait_handles[ret] );
612
            if (n == 4) return TRUE; /* it was the last running thread */
613 614
        }
        else return FALSE;
615
    }
616 617 618 619 620
}

/******************************************************************************
 * StartServiceCtrlDispatcherA [ADVAPI32.@]
 *
621
 * See StartServiceCtrlDispatcherW.
622
 */
623
BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
624 625
{
    service_data *info;
626
    unsigned int i;
627 628 629 630
    BOOL ret = TRUE;

    TRACE("%p\n", servent);

631
    if (nb_services)
632
    {
633 634 635 636 637
        SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
        return FALSE;
    }
    while (servent[nb_services].lpServiceName) nb_services++;
    services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
638

639 640 641 642
    for (i = 0; i < nb_services; i++)
    {
        DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
        DWORD sz = FIELD_OFFSET( service_data, name[len] );
643
        info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
644 645
        MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
        info->proc.a = servent[i].lpServiceProc;
646
        info->unicode = FALSE;
647
        services[i] = info;
648
    }
649

650
    service_run_main_thread();
651

652 653
    return ret;
}
654

655 656 657
/******************************************************************************
 * StartServiceCtrlDispatcherW [ADVAPI32.@]
 *
658 659 660
 *  Connects a process containing one or more services to the service control
 * manager.
 *
661
 * PARAMS
662
 *   servent [I]  A list of the service names and service procedures
663 664 665 666
 *
 * RETURNS
 *  Success: TRUE.
 *  Failure: FALSE.
667
 */
668
BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
669
{
670
    service_data *info;
671
    unsigned int i;
672 673 674 675
    BOOL ret = TRUE;

    TRACE("%p\n", servent);

676
    if (nb_services)
677
    {
678 679 680 681 682
        SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
        return FALSE;
    }
    while (servent[nb_services].lpServiceName) nb_services++;
    services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
683

684 685 686 687
    for (i = 0; i < nb_services; i++)
    {
        DWORD len = strlenW(servent[i].lpServiceName) + 1;
        DWORD sz = FIELD_OFFSET( service_data, name[len] );
688
        info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
689 690
        strcpyW(info->name, servent[i].lpServiceName);
        info->proc.w = servent[i].lpServiceProc;
691
        info->unicode = TRUE;
692
        services[i] = info;
693 694
    }

695
    service_run_main_thread();
696 697

    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
698 699
}

700 701 702
/******************************************************************************
 * LockServiceDatabase  [ADVAPI32.@]
 */
703
SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
704
{
705
    struct sc_manager *hscm;
706
    SC_RPC_LOCK hLock = NULL;
707
    DWORD err;
708 709 710

    TRACE("%p\n",hSCManager);

711 712
    hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
    if (!hscm)
713
    {
714 715
        SetLastError( ERROR_INVALID_HANDLE );
        return NULL;
716 717
    }

718 719 720 721 722 723 724 725 726
    __TRY
    {
        err = svcctl_LockServiceDatabase(hscm->hdr.server_handle, &hLock);
    }
    __EXCEPT(rpc_filter)
    {
        err = map_exception_code(GetExceptionCode());
    }
    __ENDTRY
727 728 729 730 731 732
    if (err != ERROR_SUCCESS)
    {
        SetLastError(err);
        return NULL;
    }
    return hLock;
733 734 735 736 737
}

/******************************************************************************
 * UnlockServiceDatabase  [ADVAPI32.@]
 */
738
BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
739
{
740 741 742
    DWORD err;
    SC_RPC_LOCK hRpcLock = ScLock;

743 744
    TRACE("%p\n",ScLock);

745 746 747 748 749 750 751 752 753
    __TRY
    {
        err = svcctl_UnlockServiceDatabase(&hRpcLock);
    }
    __EXCEPT(rpc_filter)
    {
        err = map_exception_code(GetExceptionCode());
    }
    __ENDTRY
754 755 756 757 758 759
    if (err != ERROR_SUCCESS)
    {
        SetLastError(err);
        return FALSE;
    }
    return TRUE;
760 761
}

762
/******************************************************************************
763
 * SetServiceStatus [ADVAPI32.@]
764 765 766 767
 *
 * PARAMS
 *   hService []
 *   lpStatus []
768
 */
769
BOOL WINAPI
770
SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
771
{
772 773
    struct sc_service *hsvc;
    DWORD err;
774

775
    TRACE("%p %x %x %x %x %x %x %x\n", hService,
776 777 778 779 780
          lpStatus->dwServiceType, lpStatus->dwCurrentState,
          lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
          lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
          lpStatus->dwWaitHint);

781 782
    hsvc = sc_handle_get_handle_data((SC_HANDLE)hService, SC_HTYPE_SERVICE);
    if (!hsvc)
783
    {
784 785
        SetLastError( ERROR_INVALID_HANDLE );
        return FALSE;
786 787
    }

788 789 790 791 792 793 794 795 796
    __TRY
    {
        err = svcctl_SetServiceStatus( hsvc->hdr.server_handle, lpStatus );
    }
    __EXCEPT(rpc_filter)
    {
        err = map_exception_code(GetExceptionCode());
    }
    __ENDTRY
797 798 799 800 801 802 803 804 805 806
    if (err != ERROR_SUCCESS)
    {
        SetLastError(err);
        return FALSE;
    }

    if (lpStatus->dwCurrentState == SERVICE_STOPPED)
        CloseServiceHandle((SC_HANDLE)hService);

    return TRUE;
807
}
Alexandre Julliard's avatar
Alexandre Julliard committed
808

809

Alexandre Julliard's avatar
Alexandre Julliard committed
810
/******************************************************************************
811
 * OpenSCManagerA [ADVAPI32.@]
Jon Griffiths's avatar
Jon Griffiths committed
812 813 814 815 816 817 818 819 820 821 822
 *
 * 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
Alexandre Julliard's avatar
Alexandre Julliard committed
823
 */
Jon Griffiths's avatar
Jon Griffiths committed
824 825
SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
                                 DWORD dwDesiredAccess )
826
{
827
    LPWSTR lpMachineNameW, lpDatabaseNameW;
828 829
    SC_HANDLE ret;

830 831 832
    lpMachineNameW = SERV_dup(lpMachineName);
    lpDatabaseNameW = SERV_dup(lpDatabaseName);
    ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
833 834
    HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
    HeapFree(GetProcessHeap(), 0, lpMachineNameW);
Alexandre Julliard's avatar
Alexandre Julliard committed
835
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
836 837
}

Alexandre Julliard's avatar
Alexandre Julliard committed
838
/******************************************************************************
839
 * OpenSCManagerW [ADVAPI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
840
 *
Jon Griffiths's avatar
Jon Griffiths committed
841
 * See OpenSCManagerA.
Alexandre Julliard's avatar
Alexandre Julliard committed
842
 */
Jon Griffiths's avatar
Jon Griffiths committed
843 844
SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
                                 DWORD dwDesiredAccess )
Alexandre Julliard's avatar
Alexandre Julliard committed
845
{
846
    struct sc_manager *manager;
847
    HKEY hReg;
848
    LONG r;
849
    DWORD new_mask = dwDesiredAccess;
850

851
    TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
Alexandre Julliard's avatar
Alexandre Julliard committed
852
          debugstr_w(lpDatabaseName), dwDesiredAccess);
853

854 855 856 857
    manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
                               sc_handle_destroy_manager );
    if (!manager)
         return NULL;
858

859 860 861 862 863 864 865 866 867
    __TRY
    {
        r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &manager->hdr.server_handle);
    }
    __EXCEPT(rpc_filter)
    {
        r = map_exception_code(GetExceptionCode());
    }
    __ENDTRY
868 869 870
    if (r!=ERROR_SUCCESS)
        goto error;

871
    r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
872 873 874
    if (r!=ERROR_SUCCESS)
        goto error;

875
    r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
876 877 878
    RegCloseKey( hReg );
    if (r!=ERROR_SUCCESS)
        goto error;
879

880 881 882
    RtlMapGenericMask(&new_mask, &scm_generic);
    manager->dwAccess = new_mask;
    TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
883

884
    return (SC_HANDLE) &manager->hdr;
885 886

error:
887
    sc_handle_free( &manager->hdr );
888
    SetLastError( r);
889
    return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
890 891
}

Alexandre Julliard's avatar
Alexandre Julliard committed
892
/******************************************************************************
893
 * ControlService [ADVAPI32.@]
Jon Griffiths's avatar
Jon Griffiths committed
894 895
 *
 * Send a control code to a service.
Alexandre Julliard's avatar
Alexandre Julliard committed
896
 *
897
 * PARAMS
Jon Griffiths's avatar
Jon Griffiths committed
898 899 900
 *   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
901
 *
Jon Griffiths's avatar
Jon Griffiths committed
902 903 904
 * RETURNS
 *   Success: TRUE.
 *   Failure: FALSE.
905 906 907 908
 *
 * BUGS
 *   Unlike M$' implementation, control requests are not serialized and may be
 *   processed asynchronously.
Alexandre Julliard's avatar
Alexandre Julliard committed
909
 */
Jon Griffiths's avatar
Jon Griffiths committed
910 911
BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
                            LPSERVICE_STATUS lpServiceStatus )
Alexandre Julliard's avatar
Alexandre Julliard committed
912
{
913
    struct sc_service *hsvc;
914
    DWORD err;
915

916
    TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
917

918 919 920 921 922 923 924
    hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
    if (!hsvc)
    {
        SetLastError( ERROR_INVALID_HANDLE );
        return FALSE;
    }

925 926 927 928 929 930 931 932 933
    __TRY
    {
        err = svcctl_ControlService(hsvc->hdr.server_handle, dwControl, lpServiceStatus);
    }
    __EXCEPT(rpc_filter)
    {
        err = map_exception_code(GetExceptionCode());
    }
    __ENDTRY
934
    if (err != ERROR_SUCCESS)
935
    {
936 937
        SetLastError(err);
        return FALSE;
938 939
    }

940
    return TRUE;
941
}
Alexandre Julliard's avatar
Alexandre Julliard committed
942 943

/******************************************************************************
944
 * CloseServiceHandle [ADVAPI32.@]
Jon Griffiths's avatar
Jon Griffiths committed
945 946
 * 
 * Close a handle to a service or the service control manager database.
Alexandre Julliard's avatar
Alexandre Julliard committed
947 948
 *
 * PARAMS
949
 *   hSCObject [I] Handle to service or service control manager database
Alexandre Julliard's avatar
Alexandre Julliard committed
950
 *
Jon Griffiths's avatar
Jon Griffiths committed
951 952 953
 * RETURNS
 *  Success: TRUE
 *  Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
954
 */
955
BOOL WINAPI
956
CloseServiceHandle( SC_HANDLE hSCObject )
Alexandre Julliard's avatar
Alexandre Julliard committed
957
{
958 959 960
    struct sc_handle *obj;
    DWORD err;

961
    TRACE("%p\n", hSCObject);
962 963 964 965 966
    if (hSCObject == NULL)
    {
        SetLastError(ERROR_INVALID_HANDLE);
        return FALSE;
    }
967

968
    obj = (struct sc_handle *)hSCObject;
969 970 971 972 973 974 975 976 977
    __TRY
    {
        err = svcctl_CloseServiceHandle(&obj->server_handle);
    }
    __EXCEPT(rpc_filter)
    {
        err = map_exception_code(GetExceptionCode());
    }
    __ENDTRY
978
    sc_handle_free( obj );
979

980 981 982 983 984
    if (err != ERROR_SUCCESS)
    {
        SetLastError(err);
        return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
985 986 987 988 989
    return TRUE;
}


/******************************************************************************
990
 * OpenServiceA [ADVAPI32.@]
Jon Griffiths's avatar
Jon Griffiths committed
991 992 993 994 995 996 997 998 999 1000 1001
 *
 * 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
Alexandre Julliard's avatar
Alexandre Julliard committed
1002
 */
Jon Griffiths's avatar
Jon Griffiths committed
1003 1004
SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
                               DWORD dwDesiredAccess )
Alexandre Julliard's avatar
Alexandre Julliard committed
1005
{
1006
    LPWSTR lpServiceNameW;
1007
    SC_HANDLE ret;
1008

1009
    TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1010 1011 1012

    lpServiceNameW = SERV_dup(lpServiceName);
    ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1013
    HeapFree(GetProcessHeap(), 0, lpServiceNameW);
Alexandre Julliard's avatar
Alexandre Julliard committed
1014 1015 1016 1017 1018
    return ret;
}


/******************************************************************************
1019
 * OpenServiceW [ADVAPI32.@]
1020
 *
Jon Griffiths's avatar
Jon Griffiths committed
1021
 * See OpenServiceA.
Alexandre Julliard's avatar
Alexandre Julliard committed
1022
 */
Jon Griffiths's avatar
Jon Griffiths committed
1023 1024
SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
                               DWORD dwDesiredAccess)
Alexandre Julliard's avatar
Alexandre Julliard committed
1025
{
1026 1027
    struct sc_manager *hscm;
    struct sc_service *hsvc;
1028
    DWORD err;
1029
    DWORD len;
1030
    DWORD new_mask = dwDesiredAccess;
1031

1032
    TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1033

1034 1035 1036 1037 1038 1039
    hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
    if (!hscm)
    {
        SetLastError( ERROR_INVALID_HANDLE );
        return FALSE;
    }
1040

1041 1042 1043 1044 1045
    if (!lpServiceName)
    {
        SetLastError(ERROR_INVALID_ADDRESS);
        return NULL;
    }
1046
    
1047 1048 1049 1050 1051
    len = strlenW(lpServiceName)+1;
    hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
                            sizeof (struct sc_service) + len*sizeof(WCHAR),
                            sc_handle_destroy_service );
    if (!hsvc)
1052
    {
1053
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1054
        return NULL;
1055
    }
1056 1057 1058 1059 1060
    strcpyW( hsvc->name, lpServiceName );

    /* add reference to SCM handle */
    hscm->hdr.ref_count++;
    hsvc->scm = hscm;
1061

1062 1063 1064 1065 1066 1067 1068 1069 1070
    __TRY
    {
        err = svcctl_OpenServiceW(hscm->hdr.server_handle, lpServiceName, dwDesiredAccess, &hsvc->hdr.server_handle);
    }
    __EXCEPT(rpc_filter)
    {
        err = map_exception_code(GetExceptionCode());
    }
    __ENDTRY
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086

    if (err != ERROR_SUCCESS)
    {
        sc_handle_free(&hsvc->hdr);
        SetLastError(err);
        return NULL;
    }

    /* for parts of advapi32 not using services.exe yet */
    RtlMapGenericMask(&new_mask, &svc_generic);
    hsvc->dwAccess = new_mask;

    err = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hsvc->hkey );
    if (err != ERROR_SUCCESS)
        ERR("Shouldn't hapen - service key for service validated by services.exe doesn't exist\n");

1087
    TRACE("returning %p\n",hsvc);
1088

1089
    return (SC_HANDLE) &hsvc->hdr;
Alexandre Julliard's avatar
Alexandre Julliard committed
1090 1091
}

1092
/******************************************************************************
1093
 * CreateServiceW [ADVAPI32.@]
1094 1095
 */
SC_HANDLE WINAPI
1096
CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1097 1098
                  LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
                  DWORD dwServiceType, DWORD dwStartType,
1099
                  DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1100 1101
                  LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
                  LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1102
                  LPCWSTR lpPassword )
Alexandre Julliard's avatar
Alexandre Julliard committed
1103
{
1104 1105
    struct sc_manager *hscm;
    struct sc_service *hsvc = NULL;
1106
    DWORD new_mask = dwDesiredAccess;
1107
    DWORD len, err;
1108
    SIZE_T passwdlen;
1109 1110

    TRACE("%p %s %s\n", hSCManager, 
1111 1112
          debugstr_w(lpServiceName), debugstr_w(lpDisplayName));

1113 1114 1115 1116
    hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
    if (!hscm)
    {
        SetLastError( ERROR_INVALID_HANDLE );
1117
        return NULL;
1118
    }
1119

1120 1121 1122 1123 1124 1125
    if (!lpServiceName || !lpBinaryPathName)
    {
        SetLastError(ERROR_INVALID_ADDRESS);
        return NULL;
    }

1126 1127 1128 1129
    if (lpPassword)
        passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
    else
        passwdlen = 0;
1130

1131 1132 1133 1134
    len = strlenW(lpServiceName)+1;
    len = sizeof (struct sc_service) + len*sizeof(WCHAR);
    hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
    if( !hsvc )
1135
    {
1136
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1137 1138
        return NULL;
    }
1139
    lstrcpyW( hsvc->name, lpServiceName );
1140

1141 1142
    hsvc->scm = hscm;
    hscm->hdr.ref_count++;
1143

1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
    __TRY
    {
        err = svcctl_CreateServiceW(hscm->hdr.server_handle, lpServiceName,
                lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
                lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (LPBYTE)lpDependencies,
                multisz_cb(lpDependencies), lpServiceStartName, (LPBYTE)lpPassword, passwdlen,
                &hsvc->hdr.server_handle);
    }
    __EXCEPT(rpc_filter)
    {
        err = map_exception_code(GetExceptionCode());
    }
    __ENDTRY
1157

1158
    if (err != ERROR_SUCCESS)
1159
    {
1160 1161
        SetLastError(err);
        sc_handle_free(&hsvc->hdr);
1162
        return NULL;
1163
    }
1164

1165 1166 1167 1168
    /* for parts of advapi32 not using services.exe yet */
    err = RegOpenKeyW(hscm->hkey, lpServiceName, &hsvc->hkey);
    if (err != ERROR_SUCCESS)
        WINE_ERR("Couldn't open key that should have been created by services.exe\n");
1169 1170 1171 1172

    RtlMapGenericMask(&new_mask, &svc_generic);
    hsvc->dwAccess = new_mask;

1173
    return (SC_HANDLE) &hsvc->hdr;
Alexandre Julliard's avatar
Alexandre Julliard committed
1174 1175 1176
}


1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
/******************************************************************************
 * 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 );

1209 1210 1211 1212 1213 1214 1215
    HeapFree( GetProcessHeap(), 0, lpServiceNameW );
    HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
    HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
    HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
    HeapFree( GetProcessHeap(), 0, lpDependenciesW );
    HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
    HeapFree( GetProcessHeap(), 0, lpPasswordW );
1216 1217 1218 1219 1220

    return r;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1221
/******************************************************************************
1222
 * DeleteService [ADVAPI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1223
 *
Jon Griffiths's avatar
Jon Griffiths committed
1224
 * Delete a service from the service control manager database.
Alexandre Julliard's avatar
Alexandre Julliard committed
1225
 *
Jon Griffiths's avatar
Jon Griffiths committed
1226 1227
 * PARAMS
 *    hService [I] Handle of the service to delete
Alexandre Julliard's avatar
Alexandre Julliard committed
1228
 *
Jon Griffiths's avatar
Jon Griffiths committed
1229 1230 1231
 * RETURNS
 *  Success: TRUE
 *  Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
1232
 */
Jon Griffiths's avatar
Jon Griffiths committed
1233
BOOL WINAPI DeleteService( SC_HANDLE hService )
Alexandre Julliard's avatar
Alexandre Julliard committed
1234
{
1235
    struct sc_service *hsvc;
1236
    DWORD err;
1237

1238 1239 1240 1241 1242 1243 1244
    hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
    if (!hsvc)
    {
        SetLastError( ERROR_INVALID_HANDLE );
        return FALSE;
    }

1245 1246 1247 1248 1249 1250 1251 1252 1253
    __TRY
    {
        err = svcctl_DeleteService(hsvc->hdr.server_handle);
    }
    __EXCEPT(rpc_filter)
    {
        err = map_exception_code(GetExceptionCode());
    }
    __ENDTRY
1254
    if (err != 0)
1255
    {
1256
        SetLastError(err);
1257 1258 1259
        return FALSE;
    }

1260 1261 1262
    /* Close the key to the service */
    RegCloseKey(hsvc->hkey);
    hsvc->hkey = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1263 1264 1265 1266 1267
    return TRUE;
}


/******************************************************************************
1268
 * StartServiceA [ADVAPI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1269
 *
Jon Griffiths's avatar
Jon Griffiths committed
1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
 * 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
Alexandre Julliard's avatar
Alexandre Julliard committed
1289
 */
1290 1291
BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
                           LPCSTR *lpServiceArgVectors )
Alexandre Julliard's avatar
Alexandre Julliard committed
1292
{
1293
    LPWSTR *lpwstr=NULL;
1294
    unsigned int i;
1295
    BOOL r;
1296

1297
    TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1298

1299
    if (dwNumServiceArgs)
1300
        lpwstr = HeapAlloc( GetProcessHeap(), 0,
1301 1302 1303
                                   dwNumServiceArgs*sizeof(LPWSTR) );

    for(i=0; i<dwNumServiceArgs; i++)
1304
        lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1305

1306
    r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1307

1308
    if (dwNumServiceArgs)
1309 1310
    {
        for(i=0; i<dwNumServiceArgs; i++)
1311
            HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1312 1313 1314
        HeapFree(GetProcessHeap(), 0, lpwstr);
    }

1315
    return r;
Alexandre Julliard's avatar
Alexandre Julliard committed
1316 1317
}

1318

1319 1320 1321 1322 1323 1324 1325 1326 1327
/******************************************************************************
 * StartServiceW [ADVAPI32.@]
 * 
 * See StartServiceA.
 */
BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
                          LPCWSTR *lpServiceArgVectors)
{
    struct sc_service *hsvc;
1328
    DWORD err;
1329

1330
    TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1331

1332 1333
    hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
    if (!hsvc)
1334
    {
1335
        SetLastError(ERROR_INVALID_HANDLE);
1336
        return FALSE;
1337 1338
    }

1339 1340 1341 1342 1343 1344 1345 1346 1347
    __TRY
    {
        err = svcctl_StartServiceW(hsvc->hdr.server_handle, dwNumServiceArgs, lpServiceArgVectors);
    }
    __EXCEPT(rpc_filter)
    {
        err = map_exception_code(GetExceptionCode());
    }
    __ENDTRY
1348
    if (err != ERROR_SUCCESS)
1349
    {
1350 1351
        SetLastError(err);
        return FALSE;
1352 1353
    }

1354
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1355 1356
}

1357
/******************************************************************************
1358
 * QueryServiceStatus [ADVAPI32.@]
1359 1360
 *
 * PARAMS
1361 1362
 *   hService        [I] Handle to service to get information about
 *   lpservicestatus [O] buffer to receive the status information for the service
1363
 *
1364
 */
1365 1366
BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
                               LPSERVICE_STATUS lpservicestatus)
1367
{
1368 1369
    SERVICE_STATUS_PROCESS SvcStatusData;
    BOOL ret;
1370
    DWORD dummy;
1371 1372

    TRACE("%p %p\n", hService, lpservicestatus);
1373

1374
    ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1375
                                sizeof(SERVICE_STATUS_PROCESS), &dummy);
1376
    if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1377
    return ret;
1378
}
1379

1380

1381 1382 1383
/******************************************************************************
 * QueryServiceStatusEx [ADVAPI32.@]
 *
Jon Griffiths's avatar
Jon Griffiths committed
1384 1385
 * Get information about a service.
 *
1386
 * PARAMS
Jon Griffiths's avatar
Jon Griffiths committed
1387 1388 1389 1390 1391 1392 1393 1394 1395 1396
 *   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
 */
1397 1398 1399 1400
BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
                        LPBYTE lpBuffer, DWORD cbBufSize,
                        LPDWORD pcbBytesNeeded)
{
1401
    struct sc_service *hsvc;
1402
    DWORD err;
1403 1404 1405 1406 1407 1408 1409 1410 1411 1412

    TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);

    hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
    if (!hsvc)
    {
        SetLastError( ERROR_INVALID_HANDLE );
        return FALSE;
    }

1413 1414 1415 1416 1417 1418 1419 1420 1421
    __TRY
    {
        err = svcctl_QueryServiceStatusEx(hsvc->hdr.server_handle, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
    }
    __EXCEPT(rpc_filter)
    {
        err = map_exception_code(GetExceptionCode());
    }
    __ENDTRY
1422
    if (err != ERROR_SUCCESS)
1423
    {
1424 1425
        SetLastError(err);
        return FALSE;
1426 1427 1428
    }

    return TRUE;
1429
}
1430 1431 1432 1433

/******************************************************************************
 * QueryServiceConfigA [ADVAPI32.@]
 */
1434 1435
BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
                                 DWORD size, LPDWORD needed )
1436
{
1437 1438 1439 1440
    DWORD n;
    LPSTR p, buffer;
    BOOL ret;
    QUERY_SERVICE_CONFIGW *configW;
1441

1442
    TRACE("%p %p %d %p\n", hService, config, size, needed);
1443

1444
    if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1445
    {
1446
        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1447 1448
        return FALSE;
    }
1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485
    configW = (QUERY_SERVICE_CONFIGW *)buffer;
    ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
    if (!ret) goto done;

    config->dwServiceType      = configW->dwServiceType;
    config->dwStartType        = configW->dwStartType;
    config->dwErrorControl     = configW->dwErrorControl;
    config->lpBinaryPathName   = NULL;
    config->lpLoadOrderGroup   = NULL;
    config->dwTagId            = configW->dwTagId;
    config->lpDependencies     = NULL;
    config->lpServiceStartName = NULL;
    config->lpDisplayName      = NULL;

    p = (LPSTR)(config + 1);
    n = size - sizeof(*config);
    ret = FALSE;

#define MAP_STR(str) \
    do { \
        if (configW->str) \
        { \
            DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
            if (!sz) goto done; \
            config->str = p; \
            p += sz; \
            n -= sz; \
        } \
    } while (0)

    MAP_STR( lpBinaryPathName );
    MAP_STR( lpLoadOrderGroup );
    MAP_STR( lpDependencies );
    MAP_STR( lpServiceStartName );
    MAP_STR( lpDisplayName );
#undef MAP_STR

1486
    *needed = p - (LPSTR)config;
1487 1488 1489 1490 1491
    ret = TRUE;

done:
    HeapFree( GetProcessHeap(), 0, buffer );
    return ret;
1492 1493
}

1494 1495 1496 1497 1498
static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
{
    DWORD cb;

    if (!*string_ptr)
1499 1500 1501 1502 1503 1504 1505 1506 1507 1508
    {
        cb = sizeof(WCHAR);
        memset(*buf, 0, cb);
    }
    else
    {
        cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
        memcpy(*buf, *string_ptr, cb);
        MIDL_user_free(*string_ptr);
    }
1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520

    *string_ptr = (LPWSTR)*buf;
    *buf += cb;

    return cb;
}

static DWORD size_string(LPWSTR string)
{
    return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
}

1521 1522 1523 1524 1525 1526 1527 1528
/******************************************************************************
 * QueryServiceConfigW [ADVAPI32.@]
 */
BOOL WINAPI 
QueryServiceConfigW( SC_HANDLE hService,
                     LPQUERY_SERVICE_CONFIGW lpServiceConfig,
                     DWORD cbBufSize, LPDWORD pcbBytesNeeded)
{
1529
    QUERY_SERVICE_CONFIGW config;
1530
    struct sc_service *hsvc;
1531 1532 1533
    DWORD total;
    DWORD err;
    BYTE *bufpos;
1534

1535
    TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1536 1537
           cbBufSize, pcbBytesNeeded);

1538 1539 1540 1541 1542 1543
    hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
    if (!hsvc)
    {
        SetLastError( ERROR_INVALID_HANDLE );
        return FALSE;
    }
1544

1545
    memset(&config, 0, sizeof(config));
1546

1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557
    __TRY
    {
        err = svcctl_QueryServiceConfigW(hsvc->hdr.server_handle, &config);
    }
    __EXCEPT(rpc_filter)
    {
        err = map_exception_code(GetExceptionCode());
    }
    __ENDTRY

    if (err != ERROR_SUCCESS)
1558
    {
1559 1560 1561
        TRACE("services.exe: error %u\n", err);
        SetLastError(err);
        return FALSE;
1562
    }
1563

1564 1565 1566 1567 1568 1569 1570
    /* calculate the size required first */
    total = sizeof (QUERY_SERVICE_CONFIGW);
    total += size_string(config.lpBinaryPathName);
    total += size_string(config.lpLoadOrderGroup);
    total += size_string(config.lpDependencies);
    total += size_string(config.lpServiceStartName);
    total += size_string(config.lpDisplayName);
1571

1572 1573
    *pcbBytesNeeded = total;

1574
    /* if there's not enough memory, return an error */
1575
    if( total > cbBufSize )
1576 1577
    {
        SetLastError( ERROR_INSUFFICIENT_BUFFER );
1578 1579 1580 1581 1582
        MIDL_user_free(config.lpBinaryPathName);
        MIDL_user_free(config.lpLoadOrderGroup);
        MIDL_user_free(config.lpDependencies);
        MIDL_user_free(config.lpServiceStartName);
        MIDL_user_free(config.lpDisplayName);
1583 1584 1585
        return FALSE;
    }

1586 1587 1588 1589 1590 1591 1592
    *lpServiceConfig = config;
    bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
    move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
    move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
    move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
    move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
    move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1593

1594 1595 1596 1597 1598
    TRACE("Image path           = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
    TRACE("Group                = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
    TRACE("Dependencies         = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
    TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
    TRACE("Display name         = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1599 1600 1601 1602

    return TRUE;
}

1603 1604 1605 1606
/******************************************************************************
 * QueryServiceConfig2A [ADVAPI32.@]
 *
 * Note
Austin English's avatar
Austin English committed
1607
 *   observed under win2k:
1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717
 *   The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
 *   required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
 */
BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
                                 DWORD size, LPDWORD needed)
{
    BOOL ret;
    LPBYTE bufferW = NULL;

    if(buffer && size)
        bufferW = HeapAlloc( GetProcessHeap(), 0, size);

    ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
    if(!ret) goto cleanup;

    switch(dwLevel) {
        case SERVICE_CONFIG_DESCRIPTION:
            {   LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
                LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
                if (configW->lpDescription) {
                    DWORD sz;
                    configA->lpDescription = (LPSTR)(configA + 1);
                    sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
                             configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
                    if (!sz) {
                        FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
                        ret = FALSE;
                        configA->lpDescription = NULL;
                    }
                }
                else configA->lpDescription = NULL;
            }
        break;
        default:
            FIXME("conversation W->A not implemented for level %d\n", dwLevel);
            ret = FALSE;
    }

cleanup:
    HeapFree( GetProcessHeap(), 0, bufferW);
    return ret;
}

/******************************************************************************
 * QueryServiceConfig2W [ADVAPI32.@]
 */
BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
                                 DWORD size, LPDWORD needed)
{
    DWORD sz, type;
    HKEY hKey;
    LONG r;
    struct sc_service *hsvc;

    if(dwLevel != SERVICE_CONFIG_DESCRIPTION) {
        if((dwLevel == SERVICE_CONFIG_DELAYED_AUTO_START_INFO) ||
           (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS) ||
           (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS_FLAG) ||
           (dwLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO) ||
           (dwLevel == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO) ||
           (dwLevel == SERVICE_CONFIG_SERVICE_SID_INFO))
            FIXME("Level %d not implemented\n", dwLevel);
        SetLastError(ERROR_INVALID_LEVEL);
        return FALSE;
    }
    if(!needed || (!buffer && size)) {
        SetLastError(ERROR_INVALID_ADDRESS);
        return FALSE;
    }

    TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);

    hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
    if (!hsvc)
    {
        SetLastError(ERROR_INVALID_HANDLE);
        return FALSE;
    }
    hKey = hsvc->hkey;

    switch(dwLevel) {
        case SERVICE_CONFIG_DESCRIPTION: {
            static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
            LPSERVICE_DESCRIPTIONW config = (LPSERVICE_DESCRIPTIONW) buffer;
            LPBYTE strbuf = NULL;
            *needed = sizeof (SERVICE_DESCRIPTIONW);
            sz = size - *needed;
            if(config && (*needed <= size))
                strbuf = (LPBYTE) (config + 1);
            r = RegQueryValueExW( hKey, szDescription, 0, &type, strbuf, &sz );
            if((r == ERROR_SUCCESS) && ( type != REG_SZ)) {
                FIXME("SERVICE_CONFIG_DESCRIPTION: don't know how to handle type %d\n", type);
                return FALSE;
            }
            *needed += sz;
            if(config) {
                if(r == ERROR_SUCCESS)
                    config->lpDescription = (LPWSTR) (config + 1);
                else
                    config->lpDescription = NULL;
            }
        }
        break;
    }
    if(*needed > size)
        SetLastError(ERROR_INSUFFICIENT_BUFFER);

    return (*needed <= size);
}

1718 1719 1720 1721 1722 1723 1724 1725 1726
/******************************************************************************
 * EnumServicesStatusA [ADVAPI32.@]
 */
BOOL WINAPI
EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
                     DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
                     DWORD cbBufSize, LPDWORD pcbBytesNeeded,
                     LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
{
1727
    FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742
          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 )
{
1743
    FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1744 1745 1746 1747 1748 1749
          dwServiceType, dwServiceState, lpServices, cbBufSize,
          pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
    SetLastError (ERROR_ACCESS_DENIED);
    return FALSE;
}

1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760
/******************************************************************************
 * EnumServicesStatusExA [ADVAPI32.@]
 */
BOOL WINAPI
EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
                      DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
{
    FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
          dwServiceType, dwServiceState, lpServices, cbBufSize,
          pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_a(pszGroupName));
1761
    if (lpServicesReturned) *lpServicesReturned = 0;
1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780
    SetLastError (ERROR_ACCESS_DENIED);
    return FALSE;
}

/******************************************************************************
 * EnumServicesStatusExW [ADVAPI32.@]
 */
BOOL WINAPI
EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
                      DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
{
    FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
          dwServiceType, dwServiceState, lpServices, cbBufSize,
          pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_w(pszGroupName));
    SetLastError (ERROR_ACCESS_DENIED);
    return FALSE;
}

1781 1782 1783
/******************************************************************************
 * GetServiceKeyNameA [ADVAPI32.@]
 */
1784 1785 1786
BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
                                LPSTR lpServiceName, LPDWORD lpcchBuffer )
{
1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802
    LPWSTR lpDisplayNameW, lpServiceNameW;
    DWORD sizeW;
    BOOL ret = FALSE;

    TRACE("%p %s %p %p\n", hSCManager,
          debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);

    lpDisplayNameW = SERV_dup(lpDisplayName);
    if (lpServiceName)
        lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
    else
        lpServiceNameW = NULL;

    sizeW = *lpcchBuffer;
    if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
    {
1803
        if (lpServiceName && *lpcchBuffer)
1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824
            lpServiceName[0] = 0;
        *lpcchBuffer = sizeW*2;  /* we can only provide an upper estimation of string length */
        goto cleanup;
    }

    if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
                        *lpcchBuffer, NULL, NULL ))
    {
        if (*lpcchBuffer && lpServiceName)
            lpServiceName[0] = 0;
        *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
        goto cleanup;
    }

    /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
    ret = TRUE;

cleanup:
    HeapFree(GetProcessHeap(), 0, lpServiceNameW);
    HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
    return ret;
1825 1826
}

1827 1828 1829
/******************************************************************************
 * GetServiceKeyNameW [ADVAPI32.@]
 */
1830 1831 1832
BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
                                LPWSTR lpServiceName, LPDWORD lpcchBuffer )
{
1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851
    struct sc_manager *hscm;
    DWORD err;

    TRACE("%p %s %p %p\n", hSCManager,
          debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);

    hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
    if (!hscm)
    {
        SetLastError(ERROR_INVALID_HANDLE);
        return FALSE;
    }

    if (!lpDisplayName)
    {
        SetLastError(ERROR_INVALID_ADDRESS);
        return FALSE;
    }

1852 1853 1854 1855 1856 1857 1858 1859 1860 1861
    __TRY
    {
        err = svcctl_GetServiceKeyNameW(hscm->hdr.server_handle,
                lpDisplayName, lpServiceName, lpServiceName ? *lpcchBuffer : 0, lpcchBuffer);
    }
    __EXCEPT(rpc_filter)
    {
        err = map_exception_code(GetExceptionCode());
    }
    __ENDTRY
1862 1863 1864 1865

    if (err)
        SetLastError(err);
    return err == ERROR_SUCCESS;
1866 1867
}

1868 1869 1870
/******************************************************************************
 * QueryServiceLockStatusA [ADVAPI32.@]
 */
1871 1872 1873 1874
BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
                                     LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
                                     DWORD cbBufSize, LPDWORD pcbBytesNeeded)
{
1875
    FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1876 1877 1878 1879

    return FALSE;
}

1880 1881 1882
/******************************************************************************
 * QueryServiceLockStatusW [ADVAPI32.@]
 */
1883 1884 1885 1886
BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
                                     LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
                                     DWORD cbBufSize, LPDWORD pcbBytesNeeded)
{
1887
    FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1888 1889 1890

    return FALSE;
}
1891 1892 1893 1894 1895 1896 1897

/******************************************************************************
 * GetServiceDisplayNameA  [ADVAPI32.@]
 */
BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
  LPSTR lpDisplayName, LPDWORD lpcchBuffer)
{
1898 1899 1900
    LPWSTR lpServiceNameW, lpDisplayNameW;
    DWORD sizeW;
    BOOL ret = FALSE;
1901 1902

    TRACE("%p %s %p %p\n", hSCManager,
1903
          debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1904

1905
    lpServiceNameW = SERV_dup(lpServiceName);
1906 1907 1908 1909
    if (lpDisplayName)
        lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
    else
        lpDisplayNameW = NULL;
1910

1911 1912
    sizeW = *lpcchBuffer;
    if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
1913
    {
1914
        if (lpDisplayName && *lpcchBuffer)
1915
            lpDisplayName[0] = 0;
1916 1917
        *lpcchBuffer = sizeW*2;  /* we can only provide an upper estimation of string length */
        goto cleanup;
1918
    }
1919 1920 1921

    if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
                        *lpcchBuffer, NULL, NULL ))
1922
    {
1923 1924
        if (*lpcchBuffer && lpDisplayName)
            lpDisplayName[0] = 0;
1925 1926
        *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
        goto cleanup;
1927 1928
    }

1929 1930 1931
    /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
     * (but if the function succeeded it means that is a good upper estimation of the size) */
    ret = TRUE;
1932

1933
cleanup:
1934
    HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1935
    HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1936
    return ret;
1937 1938 1939 1940 1941 1942 1943 1944
}

/******************************************************************************
 * GetServiceDisplayNameW  [ADVAPI32.@]
 */
BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
  LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
{
1945
    struct sc_manager *hscm;
1946
    DWORD err;
1947 1948

    TRACE("%p %s %p %p\n", hSCManager,
1949
          debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1950

1951 1952
    hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
    if (!hscm)
1953
    {
1954
        SetLastError(ERROR_INVALID_HANDLE);
1955 1956 1957
        return FALSE;
    }

1958
    if (!lpServiceName)
1959
    {
1960
        SetLastError(ERROR_INVALID_ADDRESS);
1961 1962 1963
        return FALSE;
    }

1964 1965 1966 1967 1968 1969 1970 1971 1972 1973
    __TRY
    {
        err = svcctl_GetServiceDisplayNameW(hscm->hdr.server_handle,
                lpServiceName, lpDisplayName, lpDisplayName ? *lpcchBuffer : 0, lpcchBuffer);
    }
    __EXCEPT(rpc_filter)
    {
        err = map_exception_code(GetExceptionCode());
    }
    __ENDTRY
1974

1975 1976 1977
    if (err)
        SetLastError(err);
    return err == ERROR_SUCCESS;
1978 1979
}

1980 1981 1982 1983 1984 1985 1986 1987
/******************************************************************************
 * 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)
{
1988
    struct sc_service *hsvc;
1989 1990
    DWORD cb_pwd;
    DWORD err;
1991

1992
    TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1993 1994 1995 1996
          hService, dwServiceType, dwStartType, dwErrorControl, 
          debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
          lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
          debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1997 1998 1999 2000 2001 2002 2003 2004

    hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
    if (!hsvc)
    {
        SetLastError( ERROR_INVALID_HANDLE );
        return FALSE;
    }

2005
    cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2006

2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018
    __TRY
    {
        err = svcctl_ChangeServiceConfigW(hsvc->hdr.server_handle, dwServiceType,
                dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
                (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
                (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
    }
    __EXCEPT(rpc_filter)
    {
        err = map_exception_code(GetExceptionCode());
    }
    __ENDTRY
2019

2020 2021
    if (err != ERROR_SUCCESS)
        SetLastError(err);
2022

2023
    return err == ERROR_SUCCESS;
2024 2025 2026 2027 2028 2029 2030 2031 2032 2033
}

/******************************************************************************
 * 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)
{
2034 2035 2036 2037
    LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
    LPWSTR wServiceStartName, wPassword, wDisplayName;
    BOOL r;

2038
    TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2039 2040 2041 2042
          hService, dwServiceType, dwStartType, dwErrorControl, 
          debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
          lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
          debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055

    wBinaryPathName = SERV_dup( lpBinaryPathName );
    wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
    wDependencies = SERV_dupmulti( lpDependencies );
    wServiceStartName = SERV_dup( lpServiceStartName );
    wPassword = SERV_dup( lpPassword );
    wDisplayName = SERV_dup( lpDisplayName );

    r = ChangeServiceConfigW( hService, dwServiceType,
            dwStartType, dwErrorControl, wBinaryPathName,
            wLoadOrderGroup, lpdwTagId, wDependencies,
            wServiceStartName, wPassword, wDisplayName);

2056 2057 2058 2059 2060 2061
    HeapFree( GetProcessHeap(), 0, wBinaryPathName );
    HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
    HeapFree( GetProcessHeap(), 0, wDependencies );
    HeapFree( GetProcessHeap(), 0, wServiceStartName );
    HeapFree( GetProcessHeap(), 0, wPassword );
    HeapFree( GetProcessHeap(), 0, wDisplayName );
2062 2063

    return r;
2064
}
2065 2066 2067 2068 2069 2070 2071

/******************************************************************************
 * ChangeServiceConfig2A  [ADVAPI32.@]
 */
BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
    LPVOID lpInfo)
{
2072 2073
    BOOL r = FALSE;

2074
    TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2075 2076 2077 2078 2079 2080 2081 2082 2083 2084

    if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
    {
        LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
        SERVICE_DESCRIPTIONW sdw;

        sdw.lpDescription = SERV_dup( sd->lpDescription );

        r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );

2085
        HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099
    }
    else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
    {
        LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
        SERVICE_FAILURE_ACTIONSW faw;

        faw.dwResetPeriod = fa->dwResetPeriod;
        faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
        faw.lpCommand = SERV_dup( fa->lpCommand );
        faw.cActions = fa->cActions;
        faw.lpsaActions = fa->lpsaActions;

        r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );

2100 2101
        HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
        HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2102 2103 2104 2105 2106
    }
    else
        SetLastError( ERROR_INVALID_PARAMETER );

    return r;
2107 2108 2109 2110 2111 2112 2113 2114
}

/******************************************************************************
 * ChangeServiceConfig2W  [ADVAPI32.@]
 */
BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
    LPVOID lpInfo)
{
2115
    struct sc_service *hsvc;
2116
    DWORD err;
2117 2118 2119 2120 2121 2122 2123

    hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
    if (!hsvc)
    {
        SetLastError( ERROR_INVALID_HANDLE );
        return FALSE;
    }
2124

2125
    __TRY
2126
    {
2127
        err = svcctl_ChangeServiceConfig2W( hsvc->hdr.server_handle, dwInfoLevel, lpInfo );
2128
    }
2129 2130 2131 2132 2133 2134 2135 2136 2137 2138
    __EXCEPT(rpc_filter)
    {
        err = map_exception_code(GetExceptionCode());
    }
    __ENDTRY

    if (err != ERROR_SUCCESS)
        SetLastError(err);

    return err == ERROR_SUCCESS;
2139
}
2140 2141 2142 2143 2144 2145 2146 2147 2148

/******************************************************************************
 * QueryServiceObjectSecurity [ADVAPI32.@]
 */
BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
       SECURITY_INFORMATION dwSecurityInformation,
       PSECURITY_DESCRIPTOR lpSecurityDescriptor,
       DWORD cbBufSize, LPDWORD pcbBytesNeeded)
{
2149 2150 2151 2152
    SECURITY_DESCRIPTOR descriptor;
    DWORD size;
    BOOL succ;
    ACL acl;
2153

2154
    FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2155
          lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2156

2157 2158
    if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
        FIXME("information %d not supported\n", dwSecurityInformation);
2159

2160 2161 2162 2163 2164 2165 2166 2167 2168
    InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);

    InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
    SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);

    size = cbBufSize;
    succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
    *pcbBytesNeeded = size;
    return succ;
2169 2170 2171 2172 2173 2174 2175 2176 2177
}

/******************************************************************************
 * SetServiceObjectSecurity [ADVAPI32.@]
 */
BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
       SECURITY_INFORMATION dwSecurityInformation,
       PSECURITY_DESCRIPTOR lpSecurityDescriptor)
{
2178
    FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2179
    return TRUE;
2180
}
2181

2182 2183 2184
/******************************************************************************
 * SetServiceBits [ADVAPI32.@]
 */
2185 2186 2187 2188 2189
BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
        DWORD dwServiceBits,
        BOOL bSetBitsOn,
        BOOL bUpdateImmediately)
{
2190
    FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2191 2192 2193
          bSetBitsOn, bUpdateImmediately);
    return TRUE;
}
2194

2195 2196
/* thunk for calling the RegisterServiceCtrlHandler handler function */
static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2197
{
2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209
    LPHANDLER_FUNCTION func = context;

    func( control );
    return ERROR_SUCCESS;
}

/******************************************************************************
 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
 */
SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
{
    return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2210 2211
}

2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236
/******************************************************************************
 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
 */
SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
{
    return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
}

/******************************************************************************
 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
 */
SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
{
    LPWSTR nameW;
    SERVICE_STATUS_HANDLE ret;

    nameW = SERV_dup(name);
    ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
    HeapFree( GetProcessHeap(), 0, nameW );
    return ret;
}

/******************************************************************************
 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
 */
2237 2238 2239
SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
        LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
{
2240 2241
    service_data *service;
    SC_HANDLE hService = 0;
2242
    BOOL found = FALSE;
2243 2244 2245 2246

    TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);

    EnterCriticalSection( &service_cs );
2247
    if ((service = find_service_by_name( lpServiceName )))
2248
    {
2249 2250 2251 2252
        service->handler = lpHandlerProc;
        service->context = lpContext;
        hService = service->handle;
        found = TRUE;
2253 2254 2255
    }
    LeaveCriticalSection( &service_cs );

2256
    if (!found) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2257 2258

    return (SERVICE_STATUS_HANDLE)hService;
2259
}
2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287

/******************************************************************************
 * EnumDependentServicesA [ADVAPI32.@]
 */
BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
                                    LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
        LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
{
    FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
          lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);

    *lpServicesReturned = 0;
    return TRUE;
}

/******************************************************************************
 * EnumDependentServicesW [ADVAPI32.@]
 */
BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
                                    LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
                                    LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
{
    FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
          lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);

    *lpServicesReturned = 0;
    return TRUE;
}