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