1/* 2 * Unix SMB/CIFS implementation. 3 * Service Control API Implementation 4 * 5 * Copyright (C) Marcin Krzysztof Porwit 2005. 6 * Largely Rewritten by: 7 * Copyright (C) Gerald (Jerry) Carter 2005. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 */ 23 24#include "includes.h" 25 26struct rcinit_file_information { 27 char *description; 28}; 29 30struct service_display_info { 31 const char *servicename; 32 const char *daemon; 33 const char *dispname; 34 const char *description; 35}; 36 37struct service_display_info builtin_svcs[] = { 38 { "Spooler", "smbd", "Print Spooler", "Internal service for spooling files to print devices" }, 39 { "NETLOGON", "smbd", "Net Logon", "File service providing access to policy and profile data (not remotely manageable)" }, 40 { "RemoteRegistry", "smbd", "Remote Registry Service", "Internal service providing remote access to " 41 "the Samba registry" }, 42 { "WINS", "nmbd", "Windows Internet Name Service (WINS)", "Internal service providing a " 43 "NetBIOS point-to-point name server (not remotely manageable)" }, 44 { NULL, NULL, NULL, NULL } 45}; 46 47struct service_display_info common_unix_svcs[] = { 48 { "cups", NULL, "Common Unix Printing System","Provides unified printing support for all operating systems" }, 49 { "postfix", NULL, "Internet Mail Service", "Provides support for sending and receiving electonic mail" }, 50 { "sendmail", NULL, "Internet Mail Service", "Provides support for sending and receiving electonic mail" }, 51 { "portmap", NULL, "TCP Port to RPC PortMapper",NULL }, 52 { "xinetd", NULL, "Internet Meta-Daemon", NULL }, 53 { "inet", NULL, "Internet Meta-Daemon", NULL }, 54 { "xntpd", NULL, "Network Time Service", NULL }, 55 { "ntpd", NULL, "Network Time Service", NULL }, 56 { "lpd", NULL, "BSD Print Spooler", NULL }, 57 { "nfsserver", NULL, "Network File Service", NULL }, 58 { "cron", NULL, "Scheduling Service", NULL }, 59 { "at", NULL, "Scheduling Service", NULL }, 60 { "nscd", NULL, "Name Service Cache Daemon", NULL }, 61 { "slapd", NULL, "LDAP Directory Service", NULL }, 62 { "ldap", NULL, "LDAP DIrectory Service", NULL }, 63 { "ypbind", NULL, "NIS Directory Service", NULL }, 64 { "courier-imap", NULL, "IMAP4 Mail Service", NULL }, 65 { "courier-pop3", NULL, "POP3 Mail Service", NULL }, 66 { "named", NULL, "Domain Name Service", NULL }, 67 { "bind", NULL, "Domain Name Service", NULL }, 68 { "httpd", NULL, "HTTP Server", NULL }, 69 { "apache", NULL, "HTTP Server", "Provides s highly scalable and flexible web server " 70 "capable of implementing various protocols incluing " 71 "but not limited to HTTP" }, 72 { "autofs", NULL, "Automounter", NULL }, 73 { "squid", NULL, "Web Cache Proxy ", NULL }, 74 { "perfcountd", NULL, "Performance Monitoring Daemon", NULL }, 75 { "pgsql", NULL, "PgSQL Database Server", "Provides service for SQL database from Postgresql.org" }, 76 { "arpwatch", NULL, "ARP Tables watcher", "Provides service for monitoring ARP tables for changes" }, 77 { "dhcpd", NULL, "DHCP Server", "Provides service for dynamic host configuration and IP assignment" }, 78 { "nwserv", NULL, "NetWare Server Emulator", "Provides service for emulating Novell NetWare 3.12 server" }, 79 { "proftpd", NULL, "Professional FTP Server", "Provides high configurable service for FTP connection and " 80 "file transferring" }, 81 { "ssh2", NULL, "SSH Secure Shell", "Provides service for secure connection for remote administration" }, 82 { "sshd", NULL, "SSH Secure Shell", "Provides service for secure connection for remote administration" }, 83 { NULL, NULL, NULL, NULL } 84}; 85 86 87/******************************************************************** 88********************************************************************/ 89 90static SEC_DESC* construct_service_sd( TALLOC_CTX *ctx ) 91{ 92 SEC_ACE ace[4]; 93 SEC_ACCESS mask; 94 size_t i = 0; 95 SEC_DESC *sd; 96 SEC_ACL *acl; 97 size_t sd_size; 98 99 /* basic access for Everyone */ 100 101 init_sec_access(&mask, SERVICE_READ_ACCESS ); 102 init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); 103 104 init_sec_access(&mask,SERVICE_EXECUTE_ACCESS ); 105 init_sec_ace(&ace[i++], &global_sid_Builtin_Power_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); 106 107 init_sec_access(&mask,SERVICE_ALL_ACCESS ); 108 init_sec_ace(&ace[i++], &global_sid_Builtin_Server_Operators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); 109 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, SEC_ACE_TYPE_ACCESS_ALLOWED, mask, 0); 110 111 /* create the security descriptor */ 112 113 if ( !(acl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) ) 114 return NULL; 115 116 if ( !(sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, acl, &sd_size)) ) 117 return NULL; 118 119 return sd; 120} 121 122/******************************************************************** 123 This is where we do the dirty work of filling in things like the 124 Display name, Description, etc... 125********************************************************************/ 126 127static char *get_common_service_dispname( const char *servicename ) 128{ 129 static fstring dispname; 130 int i; 131 132 for ( i=0; common_unix_svcs[i].servicename; i++ ) { 133 if ( strequal( servicename, common_unix_svcs[i].servicename ) ) { 134 fstr_sprintf( dispname, "%s (%s)", 135 common_unix_svcs[i].dispname, 136 common_unix_svcs[i].servicename ); 137 138 return dispname; 139 } 140 } 141 142 fstrcpy( dispname, servicename ); 143 144 return dispname; 145} 146 147/******************************************************************** 148********************************************************************/ 149 150static char* cleanup_string( const char *string ) 151{ 152 static pstring clean; 153 char *begin, *end; 154 155 pstrcpy( clean, string ); 156 begin = clean; 157 158 /* trim any beginning whilespace */ 159 160 while ( isspace(*begin) ) 161 begin++; 162 163 if ( *begin == '\0' ) 164 return NULL; 165 166 /* trim any trailing whitespace or carriage returns. 167 Start at the end and move backwards */ 168 169 end = begin + strlen(begin) - 1; 170 171 while ( isspace(*end) || *end=='\n' || *end=='\r' ) { 172 *end = '\0'; 173 end--; 174 } 175 176 return begin; 177} 178 179/******************************************************************** 180********************************************************************/ 181 182static BOOL read_init_file( const char *servicename, struct rcinit_file_information **service_info ) 183{ 184 struct rcinit_file_information *info; 185 pstring filepath, str; 186 XFILE *f; 187 char *p; 188 189 if ( !(info = TALLOC_ZERO_P( NULL, struct rcinit_file_information ) ) ) 190 return False; 191 192 /* attempt the file open */ 193 194 pstr_sprintf( filepath, "%s/%s/%s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR, servicename ); 195 if ( !(f = x_fopen( filepath, O_RDONLY, 0 )) ) { 196 DEBUG(0,("read_init_file: failed to open [%s]\n", filepath)); 197 TALLOC_FREE(info); 198 return False; 199 } 200 201 while ( (x_fgets( str, sizeof(str)-1, f )) != NULL ) { 202 /* ignore everything that is not a full line 203 comment starting with a '#' */ 204 205 if ( str[0] != '#' ) 206 continue; 207 208 /* Look for a line like '^#.*Description:' */ 209 210 if ( (p = strstr( str, "Description:" )) != NULL ) { 211 char *desc; 212 213 p += strlen( "Description:" ) + 1; 214 if ( !p ) 215 break; 216 217 if ( (desc = cleanup_string(p)) != NULL ) 218 info->description = talloc_strdup( info, desc ); 219 } 220 } 221 222 x_fclose( f ); 223 224 if ( !info->description ) 225 info->description = talloc_strdup( info, "External Unix Service" ); 226 227 *service_info = info; 228 229 return True; 230} 231 232/******************************************************************** 233 This is where we do the dirty work of filling in things like the 234 Display name, Description, etc... 235********************************************************************/ 236 237static void fill_service_values( const char *name, REGVAL_CTR *values ) 238{ 239 UNISTR2 data, dname, ipath, description; 240 uint32 dword; 241 pstring pstr; 242 int i; 243 244 /* These values are hardcoded in all QueryServiceConfig() replies. 245 I'm just storing them here for cosmetic purposes */ 246 247 dword = SVCCTL_AUTO_START; 248 regval_ctr_addvalue( values, "Start", REG_DWORD, (char*)&dword, sizeof(uint32)); 249 250 dword = SVCCTL_WIN32_OWN_PROC; 251 regval_ctr_addvalue( values, "Type", REG_DWORD, (char*)&dword, sizeof(uint32)); 252 253 dword = SVCCTL_SVC_ERROR_NORMAL; 254 regval_ctr_addvalue( values, "ErrorControl", REG_DWORD, (char*)&dword, sizeof(uint32)); 255 256 /* everything runs as LocalSystem */ 257 258 init_unistr2( &data, "LocalSystem", UNI_STR_TERMINATE ); 259 regval_ctr_addvalue( values, "ObjectName", REG_SZ, (char*)data.buffer, data.uni_str_len*2); 260 261 /* special considerations for internal services and the DisplayName value */ 262 263 for ( i=0; builtin_svcs[i].servicename; i++ ) { 264 if ( strequal( name, builtin_svcs[i].servicename ) ) { 265 pstr_sprintf( pstr, "%s/%s/%s",dyn_LIBDIR, SVCCTL_SCRIPT_DIR, builtin_svcs[i].daemon ); 266 init_unistr2( &ipath, pstr, UNI_STR_TERMINATE ); 267 init_unistr2( &description, builtin_svcs[i].description, UNI_STR_TERMINATE ); 268 init_unistr2( &dname, builtin_svcs[i].dispname, UNI_STR_TERMINATE ); 269 break; 270 } 271 } 272 273 /* default to an external service if we haven't found a match */ 274 275 if ( builtin_svcs[i].servicename == NULL ) { 276 struct rcinit_file_information *init_info = NULL; 277 278 pstr_sprintf( pstr, "%s/%s/%s",dyn_LIBDIR, SVCCTL_SCRIPT_DIR, name ); 279 init_unistr2( &ipath, pstr, UNI_STR_TERMINATE ); 280 281 /* lookup common unix display names */ 282 init_unistr2( &dname, get_common_service_dispname( name ), UNI_STR_TERMINATE ); 283 284 /* get info from init file itself */ 285 if ( read_init_file( name, &init_info ) ) { 286 init_unistr2( &description, init_info->description, UNI_STR_TERMINATE ); 287 TALLOC_FREE( init_info ); 288 } 289 else { 290 init_unistr2( &description, "External Unix Service", UNI_STR_TERMINATE ); 291 } 292 } 293 294 /* add the new values */ 295 296 regval_ctr_addvalue( values, "DisplayName", REG_SZ, (char*)dname.buffer, dname.uni_str_len*2); 297 regval_ctr_addvalue( values, "ImagePath", REG_SZ, (char*)ipath.buffer, ipath.uni_str_len*2); 298 regval_ctr_addvalue( values, "Description", REG_SZ, (char*)description.buffer, description.uni_str_len*2); 299 300 return; 301} 302 303/******************************************************************** 304********************************************************************/ 305 306static void add_new_svc_name( REGISTRY_KEY *key_parent, REGSUBKEY_CTR *subkeys, 307 const char *name ) 308{ 309 REGISTRY_KEY *key_service, *key_secdesc; 310 WERROR wresult; 311 pstring path; 312 REGVAL_CTR *values; 313 REGSUBKEY_CTR *svc_subkeys; 314 SEC_DESC *sd; 315 prs_struct ps; 316 317 /* add to the list and create the subkey path */ 318 319 regsubkey_ctr_addkey( subkeys, name ); 320 store_reg_keys( key_parent, subkeys ); 321 322 /* open the new service key */ 323 324 pstr_sprintf( path, "%s\\%s", KEY_SERVICES, name ); 325 wresult = regkey_open_internal( &key_service, path, get_root_nt_token(), 326 REG_KEY_ALL ); 327 if ( !W_ERROR_IS_OK(wresult) ) { 328 DEBUG(0,("add_new_svc_name: key lookup failed! [%s] (%s)\n", 329 path, dos_errstr(wresult))); 330 return; 331 } 332 333 /* add the 'Security' key */ 334 335 if ( !(svc_subkeys = TALLOC_ZERO_P( key_service, REGSUBKEY_CTR )) ) { 336 DEBUG(0,("add_new_svc_name: talloc() failed!\n")); 337 regkey_close_internal( key_service ); 338 return; 339 } 340 341 fetch_reg_keys( key_service, svc_subkeys ); 342 regsubkey_ctr_addkey( svc_subkeys, "Security" ); 343 store_reg_keys( key_service, svc_subkeys ); 344 345 /* now for the service values */ 346 347 if ( !(values = TALLOC_ZERO_P( key_service, REGVAL_CTR )) ) { 348 DEBUG(0,("add_new_svc_name: talloc() failed!\n")); 349 regkey_close_internal( key_service ); 350 return; 351 } 352 353 fill_service_values( name, values ); 354 store_reg_values( key_service, values ); 355 356 /* cleanup the service key*/ 357 358 regkey_close_internal( key_service ); 359 360 /* now add the security descriptor */ 361 362 pstr_sprintf( path, "%s\\%s\\%s", KEY_SERVICES, name, "Security" ); 363 wresult = regkey_open_internal( &key_secdesc, path, get_root_nt_token(), 364 REG_KEY_ALL ); 365 if ( !W_ERROR_IS_OK(wresult) ) { 366 DEBUG(0,("add_new_svc_name: key lookup failed! [%s] (%s)\n", 367 path, dos_errstr(wresult))); 368 regkey_close_internal( key_secdesc ); 369 return; 370 } 371 372 if ( !(values = TALLOC_ZERO_P( key_secdesc, REGVAL_CTR )) ) { 373 DEBUG(0,("add_new_svc_name: talloc() failed!\n")); 374 regkey_close_internal( key_secdesc ); 375 return; 376 } 377 378 if ( !(sd = construct_service_sd(key_secdesc)) ) { 379 DEBUG(0,("add_new_svc_name: Failed to create default sec_desc!\n")); 380 regkey_close_internal( key_secdesc ); 381 return; 382 } 383 384 /* stream the printer security descriptor */ 385 386 prs_init( &ps, RPC_MAX_PDU_FRAG_LEN, key_secdesc, MARSHALL); 387 388 if ( sec_io_desc("sec_desc", &sd, &ps, 0 ) ) { 389 uint32 offset = prs_offset( &ps ); 390 regval_ctr_addvalue( values, "Security", REG_BINARY, prs_data_p(&ps), offset ); 391 store_reg_values( key_secdesc, values ); 392 } 393 394 /* finally cleanup the Security key */ 395 396 prs_mem_free( &ps ); 397 regkey_close_internal( key_secdesc ); 398 399 return; 400} 401 402/******************************************************************** 403********************************************************************/ 404 405void svcctl_init_keys( void ) 406{ 407 const char **service_list = lp_svcctl_list(); 408 int i; 409 REGSUBKEY_CTR *subkeys; 410 REGISTRY_KEY *key = NULL; 411 WERROR wresult; 412 413 /* bad mojo here if the lookup failed. Should not happen */ 414 415 wresult = regkey_open_internal( &key, KEY_SERVICES, get_root_nt_token(), 416 REG_KEY_ALL ); 417 418 if ( !W_ERROR_IS_OK(wresult) ) { 419 DEBUG(0,("init_services_keys: key lookup failed! (%s)\n", 420 dos_errstr(wresult))); 421 return; 422 } 423 424 /* lookup the available subkeys */ 425 426 if ( !(subkeys = TALLOC_ZERO_P( key, REGSUBKEY_CTR )) ) { 427 DEBUG(0,("init_services_keys: talloc() failed!\n")); 428 regkey_close_internal( key ); 429 return; 430 } 431 432 fetch_reg_keys( key, subkeys ); 433 434 /* the builting services exist */ 435 436 for ( i=0; builtin_svcs[i].servicename; i++ ) 437 add_new_svc_name( key, subkeys, builtin_svcs[i].servicename ); 438 439 for ( i=0; service_list && service_list[i]; i++ ) { 440 441 /* only add new services */ 442 if ( regsubkey_ctr_key_exists( subkeys, service_list[i] ) ) 443 continue; 444 445 /* Add the new service key and initialize the appropriate values */ 446 447 add_new_svc_name( key, subkeys, service_list[i] ); 448 } 449 450 regkey_close_internal( key ); 451 452 /* initialize the control hooks */ 453 454 init_service_op_table(); 455 456 return; 457} 458 459/******************************************************************** 460 This is where we do the dirty work of filling in things like the 461 Display name, Description, etc...Always return a default secdesc 462 in case of any failure. 463********************************************************************/ 464 465SEC_DESC* svcctl_get_secdesc( TALLOC_CTX *ctx, const char *name, NT_USER_TOKEN *token ) 466{ 467 REGISTRY_KEY *key; 468 prs_struct ps; 469 REGVAL_CTR *values; 470 REGISTRY_VALUE *val; 471 SEC_DESC *sd = NULL; 472 SEC_DESC *ret_sd = NULL; 473 pstring path; 474 WERROR wresult; 475 476 /* now add the security descriptor */ 477 478 pstr_sprintf( path, "%s\\%s\\%s", KEY_SERVICES, name, "Security" ); 479 wresult = regkey_open_internal( &key, path, token, REG_KEY_ALL ); 480 if ( !W_ERROR_IS_OK(wresult) ) { 481 DEBUG(0,("svcctl_get_secdesc: key lookup failed! [%s] (%s)\n", 482 path, dos_errstr(wresult))); 483 return NULL; 484 } 485 486 if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) { 487 DEBUG(0,("add_new_svc_name: talloc() failed!\n")); 488 regkey_close_internal( key ); 489 return NULL; 490 } 491 492 fetch_reg_values( key, values ); 493 494 if ( !(val = regval_ctr_getvalue( values, "Security" )) ) { 495 DEBUG(6,("svcctl_get_secdesc: constructing default secdesc for service [%s]\n", 496 name)); 497 regkey_close_internal( key ); 498 return construct_service_sd( ctx ); 499 } 500 501 502 /* stream the printer security descriptor */ 503 504 prs_init( &ps, 0, key, UNMARSHALL); 505 prs_give_memory( &ps, (char *)regval_data_p(val), regval_size(val), False ); 506 507 if ( !sec_io_desc("sec_desc", &sd, &ps, 0 ) ) { 508 regkey_close_internal( key ); 509 return construct_service_sd( ctx ); 510 } 511 512 ret_sd = dup_sec_desc( ctx, sd ); 513 514 /* finally cleanup the Security key */ 515 516 prs_mem_free( &ps ); 517 regkey_close_internal( key ); 518 519 return ret_sd; 520} 521 522/******************************************************************** 523 Wrapper to make storing a Service sd easier 524********************************************************************/ 525 526BOOL svcctl_set_secdesc( TALLOC_CTX *ctx, const char *name, SEC_DESC *sec_desc, NT_USER_TOKEN *token ) 527{ 528 REGISTRY_KEY *key; 529 WERROR wresult; 530 pstring path; 531 REGVAL_CTR *values; 532 prs_struct ps; 533 BOOL ret = False; 534 535 /* now add the security descriptor */ 536 537 pstr_sprintf( path, "%s\\%s\\%s", KEY_SERVICES, name, "Security" ); 538 wresult = regkey_open_internal( &key, path, token, REG_KEY_ALL ); 539 if ( !W_ERROR_IS_OK(wresult) ) { 540 DEBUG(0,("svcctl_get_secdesc: key lookup failed! [%s] (%s)\n", 541 path, dos_errstr(wresult))); 542 return False; 543 } 544 545 if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) { 546 DEBUG(0,("add_new_svc_name: talloc() failed!\n")); 547 regkey_close_internal( key ); 548 return False; 549 } 550 551 /* stream the printer security descriptor */ 552 553 prs_init( &ps, RPC_MAX_PDU_FRAG_LEN, key, MARSHALL); 554 555 if ( sec_io_desc("sec_desc", &sec_desc, &ps, 0 ) ) { 556 uint32 offset = prs_offset( &ps ); 557 regval_ctr_addvalue( values, "Security", REG_BINARY, prs_data_p(&ps), offset ); 558 ret = store_reg_values( key, values ); 559 } 560 561 /* cleanup */ 562 563 prs_mem_free( &ps ); 564 regkey_close_internal( key); 565 566 return ret; 567} 568 569/******************************************************************** 570********************************************************************/ 571 572char* svcctl_lookup_dispname( const char *name, NT_USER_TOKEN *token ) 573{ 574 static fstring display_name; 575 REGISTRY_KEY *key; 576 REGVAL_CTR *values; 577 REGISTRY_VALUE *val; 578 pstring path; 579 WERROR wresult; 580 581 /* now add the security descriptor */ 582 583 pstr_sprintf( path, "%s\\%s", KEY_SERVICES, name ); 584 wresult = regkey_open_internal( &key, path, token, REG_KEY_READ ); 585 if ( !W_ERROR_IS_OK(wresult) ) { 586 DEBUG(0,("svcctl_lookup_dispname: key lookup failed! [%s] (%s)\n", 587 path, dos_errstr(wresult))); 588 goto fail; 589 } 590 591 if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) { 592 DEBUG(0,("svcctl_lookup_dispname: talloc() failed!\n")); 593 regkey_close_internal( key ); 594 goto fail; 595 } 596 597 fetch_reg_values( key, values ); 598 599 if ( !(val = regval_ctr_getvalue( values, "DisplayName" )) ) 600 goto fail; 601 602 rpcstr_pull( display_name, regval_data_p(val), sizeof(display_name), regval_size(val), 0 ); 603 604 regkey_close_internal( key ); 605 606 return display_name; 607 608fail: 609 /* default to returning the service name */ 610 regkey_close_internal( key ); 611 fstrcpy( display_name, name ); 612 return display_name; 613} 614 615/******************************************************************** 616********************************************************************/ 617 618char* svcctl_lookup_description( const char *name, NT_USER_TOKEN *token ) 619{ 620 static fstring description; 621 REGISTRY_KEY *key; 622 REGVAL_CTR *values; 623 REGISTRY_VALUE *val; 624 pstring path; 625 WERROR wresult; 626 627 /* now add the security descriptor */ 628 629 pstr_sprintf( path, "%s\\%s", KEY_SERVICES, name ); 630 wresult = regkey_open_internal( &key, path, token, REG_KEY_READ ); 631 if ( !W_ERROR_IS_OK(wresult) ) { 632 DEBUG(0,("svcctl_lookup_dispname: key lookup failed! [%s] (%s)\n", 633 path, dos_errstr(wresult))); 634 return NULL; 635 } 636 637 if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) { 638 DEBUG(0,("svcctl_lookup_dispname: talloc() failed!\n")); 639 regkey_close_internal( key ); 640 return NULL; 641 } 642 643 fetch_reg_values( key, values ); 644 645 if ( !(val = regval_ctr_getvalue( values, "Description" )) ) 646 fstrcpy( description, "Unix Service"); 647 else 648 rpcstr_pull( description, regval_data_p(val), sizeof(description), regval_size(val), 0 ); 649 650 regkey_close_internal( key ); 651 652 return description; 653} 654 655 656/******************************************************************** 657********************************************************************/ 658 659REGVAL_CTR* svcctl_fetch_regvalues( const char *name, NT_USER_TOKEN *token ) 660{ 661 REGISTRY_KEY *key; 662 REGVAL_CTR *values; 663 pstring path; 664 WERROR wresult; 665 666 /* now add the security descriptor */ 667 668 pstr_sprintf( path, "%s\\%s", KEY_SERVICES, name ); 669 wresult = regkey_open_internal( &key, path, token, REG_KEY_READ ); 670 if ( !W_ERROR_IS_OK(wresult) ) { 671 DEBUG(0,("svcctl_fetch_regvalues: key lookup failed! [%s] (%s)\n", 672 path, dos_errstr(wresult))); 673 return NULL; 674 } 675 676 if ( !(values = TALLOC_ZERO_P( NULL, REGVAL_CTR )) ) { 677 DEBUG(0,("svcctl_fetch_regvalues: talloc() failed!\n")); 678 regkey_close_internal( key ); 679 return NULL; 680 } 681 682 fetch_reg_values( key, values ); 683 684 regkey_close_internal( key ); 685 686 return values; 687} 688 689