1/* 2 * Unix SMB/CIFS implementation. 3 * RPC Pipe client / server routines 4 * Copyright (C) Andrew Tridgell 1992-1997. 5 * Copyright (C) Luke Kenneth Casson Leighton 1996-1997. 6 * Copyright (C) Paul Ashton 1997. 7 * Copyright (C) Jeremy Allison 2001. 8 * Copyright (C) Gerald Carter 2002. 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23 */ 24 25/* Implementation of registry functions. */ 26 27#include "includes.h" 28 29#undef DBGC_CLASS 30#define DBGC_CLASS DBGC_RPC_SRV 31 32#define REGSTR_PRODUCTTYPE "ProductType" 33#define REG_PT_WINNT "WinNT" 34#define REG_PT_LANMANNT "LanmanNT" 35#define REG_PT_SERVERNT "ServerNT" 36 37#define OUR_HANDLE(hnd) (((hnd)==NULL)?"NULL":(IVAL((hnd)->data5,4)==(uint32)sys_getpid()?"OURS":"OTHER")), \ 38((unsigned int)IVAL((hnd)->data5,4)),((unsigned int)sys_getpid()) 39 40 41static REGISTRY_KEY *regkeys_list; 42 43 44/****************************************************************** 45 free() function for REGISTRY_KEY 46 *****************************************************************/ 47 48static void free_regkey_info(void *ptr) 49{ 50 REGISTRY_KEY *info = (REGISTRY_KEY*)ptr; 51 52 DLIST_REMOVE(regkeys_list, info); 53 54 SAFE_FREE(info); 55} 56 57/****************************************************************** 58 Find a registry key handle and return a REGISTRY_KEY 59 *****************************************************************/ 60 61static REGISTRY_KEY *find_regkey_index_by_hnd(pipes_struct *p, POLICY_HND *hnd) 62{ 63 REGISTRY_KEY *regkey = NULL; 64 65 if(!find_policy_by_hnd(p,hnd,(void **)®key)) { 66 DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: ")); 67 return NULL; 68 } 69 70 return regkey; 71} 72 73 74/******************************************************************* 75 Function for open a new registry handle and creating a handle 76 Note that P should be valid & hnd should already have space 77 78 When we open a key, we store the full path to the key as 79 HK[LM|U]\<key>\<key>\... 80 *******************************************************************/ 81 82static WERROR open_registry_key(pipes_struct *p, POLICY_HND *hnd, REGISTRY_KEY *parent, 83 const char *subkeyname, uint32 access_granted ) 84{ 85 REGISTRY_KEY *regkey = NULL; 86 WERROR result = WERR_OK; 87 REGSUBKEY_CTR subkeys; 88 pstring subkeyname2; 89 int subkey_len; 90 91 DEBUG(7,("open_registry_key: name = [%s][%s]\n", 92 parent ? parent->name : "NULL", subkeyname)); 93 94 /* strip any trailing '\'s */ 95 pstrcpy( subkeyname2, subkeyname ); 96 subkey_len = strlen ( subkeyname2 ); 97 if ( subkey_len && subkeyname2[subkey_len-1] == '\\' ) 98 subkeyname2[subkey_len-1] = '\0'; 99 100 if ((regkey=SMB_MALLOC_P(REGISTRY_KEY)) == NULL) 101 return WERR_NOMEM; 102 103 ZERO_STRUCTP( regkey ); 104 105 /* 106 * very crazy, but regedit.exe on Win2k will attempt to call 107 * REG_OPEN_ENTRY with a keyname of "". We should return a new 108 * (second) handle here on the key->name. regedt32.exe does 109 * not do this stupidity. --jerry 110 */ 111 112 if ( !subkey_len ) { 113 pstrcpy( regkey->name, parent->name ); 114 } 115 else { 116 pstrcpy( regkey->name, "" ); 117 if ( parent ) { 118 pstrcat( regkey->name, parent->name ); 119 pstrcat( regkey->name, "\\" ); 120 } 121 pstrcat( regkey->name, subkeyname2 ); 122 } 123 124 /* Look up the table of registry I/O operations */ 125 126 if ( !(regkey->hook = reghook_cache_find( regkey->name )) ) { 127 DEBUG(0,("open_registry_key: Failed to assigned a REGISTRY_HOOK to [%s]\n", 128 regkey->name )); 129 return WERR_BADFILE; 130 } 131 132 /* check if the path really exists; failed is indicated by -1 */ 133 /* if the subkey count failed, bail out */ 134 135 ZERO_STRUCTP( &subkeys ); 136 137 regsubkey_ctr_init( &subkeys ); 138 139 if ( fetch_reg_keys( regkey, &subkeys ) == -1 ) { 140 141 /* don't really know what to return here */ 142 result = WERR_BADFILE; 143 } 144 else { 145 /* 146 * This would previously return NT_STATUS_TOO_MANY_SECRETS 147 * that doesn't sound quite right to me --jerry 148 */ 149 150 if ( !create_policy_hnd( p, hnd, free_regkey_info, regkey ) ) 151 result = WERR_BADFILE; 152 } 153 154 /* clean up */ 155 156 regsubkey_ctr_destroy( &subkeys ); 157 158 if ( ! NT_STATUS_IS_OK(result) ) 159 SAFE_FREE( regkey ); 160 else 161 DLIST_ADD( regkeys_list, regkey ); 162 163 164 DEBUG(7,("open_registry_key: exit\n")); 165 166 return result; 167} 168 169/******************************************************************* 170 Function for open a new registry handle and creating a handle 171 Note that P should be valid & hnd should already have space 172 *******************************************************************/ 173 174static BOOL close_registry_key(pipes_struct *p, POLICY_HND *hnd) 175{ 176 REGISTRY_KEY *regkey = find_regkey_index_by_hnd(p, hnd); 177 178 if ( !regkey ) { 179 DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd))); 180 return False; 181 } 182 183 close_policy_hnd(p, hnd); 184 185 return True; 186} 187 188/******************************************************************** 189 retrieve information about the subkeys 190 *******************************************************************/ 191 192static BOOL get_subkey_information( REGISTRY_KEY *key, uint32 *maxnum, uint32 *maxlen ) 193{ 194 int num_subkeys, i; 195 uint32 max_len; 196 REGSUBKEY_CTR subkeys; 197 uint32 len; 198 199 if ( !key ) 200 return False; 201 202 ZERO_STRUCTP( &subkeys ); 203 204 regsubkey_ctr_init( &subkeys ); 205 206 if ( fetch_reg_keys( key, &subkeys ) == -1 ) 207 return False; 208 209 /* find the longest string */ 210 211 max_len = 0; 212 num_subkeys = regsubkey_ctr_numkeys( &subkeys ); 213 214 for ( i=0; i<num_subkeys; i++ ) { 215 len = strlen( regsubkey_ctr_specific_key(&subkeys, i) ); 216 max_len = MAX(max_len, len); 217 } 218 219 *maxnum = num_subkeys; 220 *maxlen = max_len*2; 221 222 regsubkey_ctr_destroy( &subkeys ); 223 224 return True; 225} 226 227/******************************************************************** 228 retrieve information about the values. We don't store values 229 here. The registry tdb is intended to be a frontend to oether 230 Samba tdb's (such as ntdrivers.tdb). 231 *******************************************************************/ 232 233static BOOL get_value_information( REGISTRY_KEY *key, uint32 *maxnum, 234 uint32 *maxlen, uint32 *maxsize ) 235{ 236 REGVAL_CTR values; 237 REGISTRY_VALUE *val; 238 uint32 sizemax, lenmax; 239 int i, num_values; 240 241 if ( !key ) 242 return False; 243 244 245 ZERO_STRUCTP( &values ); 246 247 regval_ctr_init( &values ); 248 249 if ( fetch_reg_values( key, &values ) == -1 ) 250 return False; 251 252 lenmax = sizemax = 0; 253 num_values = regval_ctr_numvals( &values ); 254 255 val = regval_ctr_specific_value( &values, 0 ); 256 257 for ( i=0; i<num_values && val; i++ ) 258 { 259 lenmax = MAX(lenmax, strlen(val->valuename)+1 ); 260 sizemax = MAX(sizemax, val->size ); 261 262 val = regval_ctr_specific_value( &values, i ); 263 } 264 265 *maxnum = num_values; 266 *maxlen = lenmax; 267 *maxsize = sizemax; 268 269 regval_ctr_destroy( &values ); 270 271 return True; 272} 273 274 275/******************************************************************** 276 reg_close 277 ********************************************************************/ 278 279WERROR _reg_close(pipes_struct *p, REG_Q_CLOSE *q_u, REG_R_CLOSE *r_u) 280{ 281 /* set up the REG unknown_1 response */ 282 ZERO_STRUCT(r_u->pol); 283 284 /* close the policy handle */ 285 if (!close_registry_key(p, &q_u->pol)) 286 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */ 287 288 return WERR_OK; 289} 290 291/******************************************************************* 292 ********************************************************************/ 293 294WERROR _reg_open_hklm(pipes_struct *p, REG_Q_OPEN_HKLM *q_u, REG_R_OPEN_HKLM *r_u) 295{ 296 return open_registry_key( p, &r_u->pol, NULL, KEY_HKLM, 0x0 ); 297} 298 299/******************************************************************* 300 ********************************************************************/ 301 302WERROR _reg_open_hkcr(pipes_struct *p, REG_Q_OPEN_HKCR *q_u, REG_R_OPEN_HKCR *r_u) 303{ 304 return open_registry_key( p, &r_u->pol, NULL, KEY_HKCR, 0x0 ); 305} 306 307/******************************************************************* 308 ********************************************************************/ 309 310WERROR _reg_open_hku(pipes_struct *p, REG_Q_OPEN_HKU *q_u, REG_R_OPEN_HKU *r_u) 311{ 312 return open_registry_key( p, &r_u->pol, NULL, KEY_HKU, 0x0 ); 313} 314 315/******************************************************************* 316 reg_reply_open_entry 317 ********************************************************************/ 318 319WERROR _reg_open_entry(pipes_struct *p, REG_Q_OPEN_ENTRY *q_u, REG_R_OPEN_ENTRY *r_u) 320{ 321 POLICY_HND pol; 322 fstring name; 323 REGISTRY_KEY *key = find_regkey_index_by_hnd(p, &q_u->pol); 324 WERROR result; 325 326 DEBUG(5,("reg_open_entry: Enter\n")); 327 328 if ( !key ) 329 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */ 330 331 rpcstr_pull(name,q_u->uni_name.buffer,sizeof(name),q_u->uni_name.uni_str_len*2,0); 332 333 result = open_registry_key( p, &pol, key, name, 0x0 ); 334 335 init_reg_r_open_entry( r_u, &pol, result ); 336 337 DEBUG(5,("reg_open_entry: Exit\n")); 338 339 return r_u->status; 340} 341 342/******************************************************************* 343 reg_reply_info 344 ********************************************************************/ 345 346WERROR _reg_info(pipes_struct *p, REG_Q_INFO *q_u, REG_R_INFO *r_u) 347{ 348 WERROR status = WERR_BADFILE; 349 fstring name; 350 const char *value_ascii = ""; 351 fstring value; 352 int value_length; 353 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol ); 354 REGISTRY_VALUE *val = NULL; 355 REGVAL_CTR regvals; 356 int i; 357 358 DEBUG(5,("_reg_info: Enter\n")); 359 360 if ( !regkey ) 361 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */ 362 363 DEBUG(7,("_reg_info: policy key name = [%s]\n", regkey->name)); 364 365 rpcstr_pull(name, q_u->uni_type.buffer, sizeof(name), q_u->uni_type.uni_str_len*2, 0); 366 367 DEBUG(5,("reg_info: looking up value: [%s]\n", name)); 368 369 ZERO_STRUCTP( ®vals ); 370 371 regval_ctr_init( ®vals ); 372 373 /* couple of hard coded registry values */ 374 375 if ( strequal(name, "RefusePasswordChange") ) { 376 uint32 dwValue; 377 378 if ( (val = SMB_MALLOC_P(REGISTRY_VALUE)) == NULL ) { 379 DEBUG(0,("_reg_info: malloc() failed!\n")); 380 return WERR_NOMEM; 381 } 382 383 if (!account_policy_get(AP_REFUSE_MACHINE_PW_CHANGE, &dwValue)) 384 dwValue = 0; 385 regval_ctr_addvalue(®vals, "RefusePasswordChange", 386 REG_DWORD, 387 (const char*)&dwValue, sizeof(dwValue)); 388 val = dup_registry_value( 389 regval_ctr_specific_value( ®vals, 0 ) ); 390 391 status = WERR_OK; 392 393 goto out; 394 } 395 396 if ( strequal(name, REGSTR_PRODUCTTYPE) ) { 397 /* This makes the server look like a member server to clients */ 398 /* which tells clients that we have our own local user and */ 399 /* group databases and helps with ACL support. */ 400 401 switch (lp_server_role()) { 402 case ROLE_DOMAIN_PDC: 403 case ROLE_DOMAIN_BDC: 404 value_ascii = REG_PT_LANMANNT; 405 break; 406 case ROLE_STANDALONE: 407 value_ascii = REG_PT_SERVERNT; 408 break; 409 case ROLE_DOMAIN_MEMBER: 410 value_ascii = REG_PT_WINNT; 411 break; 412 } 413 value_length = push_ucs2(value, value, value_ascii, 414 sizeof(value), 415 STR_TERMINATE|STR_NOALIGN); 416 regval_ctr_addvalue(®vals, REGSTR_PRODUCTTYPE, REG_SZ, 417 value, value_length); 418 419 val = dup_registry_value( regval_ctr_specific_value( ®vals, 0 ) ); 420 421 status = WERR_OK; 422 423 goto out; 424 } 425 426 /* else fall back to actually looking up the value */ 427 428 for ( i=0; fetch_reg_values_specific(regkey, &val, i); i++ ) 429 { 430 DEBUG(10,("_reg_info: Testing value [%s]\n", val->valuename)); 431 if ( StrCaseCmp( val->valuename, name ) == 0 ) { 432 DEBUG(10,("_reg_info: Found match for value [%s]\n", name)); 433 status = WERR_OK; 434 break; 435 } 436 437 free_registry_value( val ); 438 } 439 440 441out: 442 new_init_reg_r_info(q_u->ptr_buf, r_u, val, status); 443 444 regval_ctr_destroy( ®vals ); 445 free_registry_value( val ); 446 447 DEBUG(5,("_reg_info: Exit\n")); 448 449 return status; 450} 451 452 453/***************************************************************************** 454 Implementation of REG_QUERY_KEY 455 ****************************************************************************/ 456 457WERROR _reg_query_key(pipes_struct *p, REG_Q_QUERY_KEY *q_u, REG_R_QUERY_KEY *r_u) 458{ 459 WERROR status = WERR_OK; 460 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol ); 461 462 DEBUG(5,("_reg_query_key: Enter\n")); 463 464 if ( !regkey ) 465 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */ 466 467 if ( !get_subkey_information( regkey, &r_u->num_subkeys, &r_u->max_subkeylen ) ) 468 return WERR_ACCESS_DENIED; 469 470 if ( !get_value_information( regkey, &r_u->num_values, &r_u->max_valnamelen, &r_u->max_valbufsize ) ) 471 return WERR_ACCESS_DENIED; 472 473 474 r_u->sec_desc = 0x00000078; /* size for key's sec_desc */ 475 476 /* Win9x set this to 0x0 since it does not keep timestamps. 477 Doing the same here for simplicity --jerry */ 478 479 ZERO_STRUCT(r_u->mod_time); 480 481 DEBUG(5,("_reg_query_key: Exit\n")); 482 483 return status; 484} 485 486 487/***************************************************************************** 488 Implementation of REG_UNKNOWN_1A 489 ****************************************************************************/ 490 491WERROR _reg_unknown_1a(pipes_struct *p, REG_Q_UNKNOWN_1A *q_u, REG_R_UNKNOWN_1A *r_u) 492{ 493 WERROR status = WERR_OK; 494 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol ); 495 496 DEBUG(5,("_reg_unknown_1a: Enter\n")); 497 498 if ( !regkey ) 499 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */ 500 501 r_u->unknown = 0x00000005; /* seems to be consistent...no idea what it means */ 502 503 DEBUG(5,("_reg_unknown_1a: Exit\n")); 504 505 return status; 506} 507 508 509/***************************************************************************** 510 Implementation of REG_ENUM_KEY 511 ****************************************************************************/ 512 513WERROR _reg_enum_key(pipes_struct *p, REG_Q_ENUM_KEY *q_u, REG_R_ENUM_KEY *r_u) 514{ 515 WERROR status = WERR_OK; 516 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol ); 517 char *subkey = NULL; 518 519 520 DEBUG(5,("_reg_enum_key: Enter\n")); 521 522 if ( !regkey ) 523 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */ 524 525 DEBUG(8,("_reg_enum_key: enumerating key [%s]\n", regkey->name)); 526 527 if ( !fetch_reg_keys_specific( regkey, &subkey, q_u->key_index ) ) 528 { 529 status = WERR_NO_MORE_ITEMS; 530 goto done; 531 } 532 533 DEBUG(10,("_reg_enum_key: retrieved subkey named [%s]\n", subkey)); 534 535 /* subkey has the string name now */ 536 537 init_reg_r_enum_key( r_u, subkey, q_u->unknown_1, q_u->unknown_2 ); 538 539 DEBUG(5,("_reg_enum_key: Exit\n")); 540 541done: 542 SAFE_FREE( subkey ); 543 return status; 544} 545 546/***************************************************************************** 547 Implementation of REG_ENUM_VALUE 548 ****************************************************************************/ 549 550WERROR _reg_enum_value(pipes_struct *p, REG_Q_ENUM_VALUE *q_u, REG_R_ENUM_VALUE *r_u) 551{ 552 WERROR status = WERR_OK; 553 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol ); 554 REGISTRY_VALUE *val; 555 556 557 DEBUG(5,("_reg_enum_value: Enter\n")); 558 559 if ( !regkey ) 560 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */ 561 562 DEBUG(8,("_reg_enum_key: enumerating values for key [%s]\n", regkey->name)); 563 564 if ( !fetch_reg_values_specific( regkey, &val, q_u->val_index ) ) 565 { 566 status = WERR_NO_MORE_ITEMS; 567 goto done; 568 } 569 570 DEBUG(10,("_reg_enum_value: retrieved value named [%s]\n", val->valuename)); 571 572 /* subkey has the string name now */ 573 574 init_reg_r_enum_val( r_u, val ); 575 576 577 DEBUG(5,("_reg_enum_value: Exit\n")); 578 579done: 580 free_registry_value( val ); 581 582 return status; 583} 584 585 586/******************************************************************* 587 reg_shutdwon 588 ********************************************************************/ 589 590#define SHUTDOWN_R_STRING "-r" 591#define SHUTDOWN_F_STRING "-f" 592 593 594WERROR _reg_shutdown(pipes_struct *p, REG_Q_SHUTDOWN *q_u, REG_R_SHUTDOWN *r_u) 595{ 596 WERROR status = WERR_OK; 597 pstring shutdown_script; 598 UNISTR2 unimsg = q_u->uni_msg; 599 pstring message; 600 pstring chkmsg; 601 fstring timeout; 602 fstring r; 603 fstring f; 604 605 /* message */ 606 rpcstr_pull (message, unimsg.buffer, sizeof(message), unimsg.uni_str_len*2,0); 607 /* security check */ 608 alpha_strcpy (chkmsg, message, NULL, sizeof(message)); 609 /* timeout */ 610 fstr_sprintf(timeout, "%d", q_u->timeout); 611 /* reboot */ 612 fstr_sprintf(r, (q_u->reboot) ? SHUTDOWN_R_STRING : ""); 613 /* force */ 614 fstr_sprintf(f, (q_u->force) ? SHUTDOWN_F_STRING : ""); 615 616 pstrcpy(shutdown_script, lp_shutdown_script()); 617 618 if(*shutdown_script) { 619 int shutdown_ret; 620 SE_PRIV se_shutdown = SE_REMOTE_SHUTDOWN; 621 BOOL can_shutdown; 622 623 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_shutdown ); 624 625 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/ 626 if ( can_shutdown ) 627 become_root(); 628 all_string_sub(shutdown_script, "%m", chkmsg, sizeof(shutdown_script)); 629 all_string_sub(shutdown_script, "%t", timeout, sizeof(shutdown_script)); 630 all_string_sub(shutdown_script, "%r", r, sizeof(shutdown_script)); 631 all_string_sub(shutdown_script, "%f", f, sizeof(shutdown_script)); 632 shutdown_ret = smbrun(shutdown_script,NULL); 633 DEBUG(3,("_reg_shutdown: Running the command `%s' gave %d\n",shutdown_script,shutdown_ret)); 634 if ( can_shutdown ) 635 unbecome_root(); 636 /********** END SeRemoteShutdownPrivilege BLOCK **********/ 637 } 638 639 return status; 640} 641 642/******************************************************************* 643 reg_abort_shutdwon 644 ********************************************************************/ 645 646WERROR _reg_abort_shutdown(pipes_struct *p, REG_Q_ABORT_SHUTDOWN *q_u, REG_R_ABORT_SHUTDOWN *r_u) 647{ 648 WERROR status = WERR_OK; 649 pstring abort_shutdown_script; 650 651 pstrcpy(abort_shutdown_script, lp_abort_shutdown_script()); 652 653 if(*abort_shutdown_script) { 654 int abort_shutdown_ret; 655 SE_PRIV se_shutdown = SE_REMOTE_SHUTDOWN; 656 BOOL can_shutdown; 657 658 can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_shutdown ); 659 660 /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/ 661 if ( can_shutdown ) 662 become_root(); 663 abort_shutdown_ret = smbrun(abort_shutdown_script,NULL); 664 DEBUG(3,("_reg_abort_shutdown: Running the command `%s' gave %d\n",abort_shutdown_script,abort_shutdown_ret)); 665 if ( can_shutdown ) 666 unbecome_root(); 667 /********** END SeRemoteShutdownPrivilege BLOCK **********/ 668 669 } 670 671 return status; 672} 673 674/******************************************************************* 675 REG_SAVE_KEY (0x14) 676 ********************************************************************/ 677 678WERROR _reg_save_key(pipes_struct *p, REG_Q_SAVE_KEY *q_u, REG_R_SAVE_KEY *r_u) 679{ 680 REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol ); 681 682 DEBUG(5,("_reg_save_key: Enter\n")); 683 684 /* 685 * basically this is a no op function which just gverifies 686 * that the client gave us a valid registry key handle 687 */ 688 689 if ( !regkey ) 690 return WERR_BADFID; /* This will be reported as an RPC fault anyway. */ 691 692 DEBUG(8,("_reg_save_key: berifying backup of key [%s]\n", regkey->name)); 693 694 695 return WERR_OK; 696} 697 698 699