1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Windows Registry RPC (WINREG) server-side interface. 28 * 29 * The registry is a database with a hierarchical structure similar to 30 * a file system, with keys in place of directories and values in place 31 * of files. The top level keys are known as root keys and each key can 32 * contain subkeys and values. As with directories and sub-directories, 33 * the terms key and subkey are used interchangeably. Values, analogous 34 * to files, contain data. 35 * 36 * A specific subkey can be identifies by its fully qualified name (FQN), 37 * which is analogous to a file system path. In the registry, the key 38 * separator is the '\' character, which is reserved and cannot appear 39 * in key or value names. Registry names are case-insensitive. 40 * 41 * For example: HKEY_LOCAL_MACHINE\System\CurrentControlSet 42 * 43 * The HKEY_LOCAL_MACHINE root key contains a subkey called System, and 44 * System contains a subkey called CurrentControlSet. 45 * 46 * The WINREG RPC interface returns Win32 error codes. 47 */ 48 49 #include <sys/utsname.h> 50 #include <strings.h> 51 52 #include <smbsrv/libsmb.h> 53 #include <smbsrv/ntstatus.h> 54 #include <smbsrv/nterror.h> 55 #include <smbsrv/nmpipes.h> 56 #include <smbsrv/libmlsvc.h> 57 #include <smbsrv/ndl/winreg.ndl> 58 59 /* 60 * List of supported registry keys (case-insensitive). 61 */ 62 static char *winreg_keys[] = { 63 "HKLM", 64 "HKU", 65 "HKLM\\SOFTWARE", 66 "HKLM\\SYSTEM", 67 "Application", 68 "Security", 69 "System", 70 "CurrentControlSet", 71 "System\\CurrentControlSet\\Services\\Eventlog", 72 "System\\CurrentControlSet\\Services\\Eventlog\\Application", 73 "System\\CurrentControlSet\\Services\\Eventlog\\Security", 74 "System\\CurrentControlSet\\Services\\Eventlog\\System", 75 "System\\CurrentControlSet\\Control\\ProductOptions", 76 "SOFTWARE", 77 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion" 78 }; 79 80 typedef struct winreg_subkey { 81 list_node_t sk_lnd; 82 ndr_hdid_t sk_handle; 83 char sk_name[MAXPATHLEN]; 84 boolean_t sk_predefined; 85 } winreg_subkey_t; 86 87 typedef struct winreg_keylist { 88 list_t kl_list; 89 int kl_count; 90 } winreg_keylist_t; 91 92 static winreg_keylist_t winreg_keylist; 93 94 static boolean_t winreg_key_has_subkey(const char *); 95 static char *winreg_enum_subkey(ndr_xa_t *, const char *, uint32_t); 96 static char *winreg_lookup_value(const char *); 97 static uint32_t winreg_sd_format(smb_sd_t *); 98 uint32_t srvsvc_sd_set_relative(smb_sd_t *, uint8_t *); 99 100 static int winreg_s_OpenHKCR(void *, ndr_xa_t *); 101 static int winreg_s_OpenHKCU(void *, ndr_xa_t *); 102 static int winreg_s_OpenHKLM(void *, ndr_xa_t *); 103 static int winreg_s_OpenHKPD(void *, ndr_xa_t *); 104 static int winreg_s_OpenHKU(void *, ndr_xa_t *); 105 static int winreg_s_OpenHKCC(void *, ndr_xa_t *); 106 static int winreg_s_OpenHKDD(void *, ndr_xa_t *); 107 static int winreg_s_OpenHKPT(void *, ndr_xa_t *); 108 static int winreg_s_OpenHKPN(void *, ndr_xa_t *); 109 static int winreg_s_OpenHK(void *, ndr_xa_t *, const char *); 110 static int winreg_s_Close(void *, ndr_xa_t *); 111 static int winreg_s_CreateKey(void *, ndr_xa_t *); 112 static int winreg_s_DeleteKey(void *, ndr_xa_t *); 113 static int winreg_s_DeleteValue(void *, ndr_xa_t *); 114 static int winreg_s_EnumKey(void *, ndr_xa_t *); 115 static int winreg_s_EnumValue(void *, ndr_xa_t *); 116 static int winreg_s_FlushKey(void *, ndr_xa_t *); 117 static int winreg_s_GetKeySec(void *, ndr_xa_t *); 118 static int winreg_s_NotifyChange(void *, ndr_xa_t *); 119 static int winreg_s_OpenKey(void *, ndr_xa_t *); 120 static int winreg_s_QueryKey(void *, ndr_xa_t *); 121 static int winreg_s_QueryValue(void *, ndr_xa_t *); 122 static int winreg_s_SetKeySec(void *, ndr_xa_t *); 123 static int winreg_s_CreateValue(void *, ndr_xa_t *); 124 static int winreg_s_Shutdown(void *, ndr_xa_t *); 125 static int winreg_s_AbortShutdown(void *, ndr_xa_t *); 126 static int winreg_s_GetVersion(void *, ndr_xa_t *); 127 128 static ndr_stub_table_t winreg_stub_table[] = { 129 { winreg_s_OpenHKCR, WINREG_OPNUM_OpenHKCR }, 130 { winreg_s_OpenHKCU, WINREG_OPNUM_OpenHKCU }, 131 { winreg_s_OpenHKLM, WINREG_OPNUM_OpenHKLM }, 132 { winreg_s_OpenHKPD, WINREG_OPNUM_OpenHKPD }, 133 { winreg_s_OpenHKU, WINREG_OPNUM_OpenHKUsers }, 134 { winreg_s_Close, WINREG_OPNUM_Close }, 135 { winreg_s_CreateKey, WINREG_OPNUM_CreateKey }, 136 { winreg_s_DeleteKey, WINREG_OPNUM_DeleteKey }, 137 { winreg_s_DeleteValue, WINREG_OPNUM_DeleteValue }, 138 { winreg_s_EnumKey, WINREG_OPNUM_EnumKey }, 139 { winreg_s_EnumValue, WINREG_OPNUM_EnumValue }, 140 { winreg_s_FlushKey, WINREG_OPNUM_FlushKey }, 141 { winreg_s_GetKeySec, WINREG_OPNUM_GetKeySec }, 142 { winreg_s_NotifyChange, WINREG_OPNUM_NotifyChange }, 143 { winreg_s_OpenKey, WINREG_OPNUM_OpenKey }, 144 { winreg_s_QueryKey, WINREG_OPNUM_QueryKey }, 145 { winreg_s_QueryValue, WINREG_OPNUM_QueryValue }, 146 { winreg_s_SetKeySec, WINREG_OPNUM_SetKeySec }, 147 { winreg_s_CreateValue, WINREG_OPNUM_CreateValue }, 148 { winreg_s_Shutdown, WINREG_OPNUM_Shutdown }, 149 { winreg_s_AbortShutdown, WINREG_OPNUM_AbortShutdown }, 150 { winreg_s_GetVersion, WINREG_OPNUM_GetVersion }, 151 { winreg_s_OpenHKCC, WINREG_OPNUM_OpenHKCC }, 152 { winreg_s_OpenHKDD, WINREG_OPNUM_OpenHKDD }, 153 { winreg_s_OpenHKPT, WINREG_OPNUM_OpenHKPT }, 154 { winreg_s_OpenHKPN, WINREG_OPNUM_OpenHKPN }, 155 {0} 156 }; 157 158 static ndr_service_t winreg_service = { 159 "Winreg", /* name */ 160 "Windows Registry", /* desc */ 161 "\\winreg", /* endpoint */ 162 PIPE_WINREG, /* sec_addr_port */ 163 "338cd001-2244-31f1-aaaa-900038001003", 1, /* abstract */ 164 NDR_TRANSFER_SYNTAX_UUID, 2, /* transfer */ 165 0, /* no bind_instance_size */ 166 0, /* no bind_req() */ 167 0, /* no unbind_and_close() */ 168 0, /* use generic_call_stub() */ 169 &TYPEINFO(winreg_interface), /* interface ti */ 170 winreg_stub_table /* stub_table */ 171 }; 172 173 static char winreg_sysname[SYS_NMLN]; 174 175 /* 176 * winreg_initialize 177 * 178 * Initialize and register the WINREG RPC interface with the RPC runtime 179 * library. It must be called in order to use either the client side 180 * or the server side functions. 181 */ 182 void 183 winreg_initialize(void) 184 { 185 winreg_subkey_t *key; 186 struct utsname name; 187 char *sysname; 188 int i; 189 190 list_create(&winreg_keylist.kl_list, sizeof (winreg_subkey_t), 191 offsetof(winreg_subkey_t, sk_lnd)); 192 winreg_keylist.kl_count = 0; 193 194 for (i = 0; i < sizeof (winreg_keys)/sizeof (winreg_keys[0]); ++i) { 195 if ((key = malloc(sizeof (winreg_subkey_t))) != NULL) { 196 bzero(key, sizeof (winreg_subkey_t)); 197 (void) strlcpy(key->sk_name, winreg_keys[i], 198 MAXPATHLEN); 199 key->sk_predefined = B_TRUE; 200 list_insert_tail(&winreg_keylist.kl_list, key); 201 ++winreg_keylist.kl_count; 202 } 203 } 204 205 if (uname(&name) < 0) 206 sysname = "Solaris"; 207 else 208 sysname = name.sysname; 209 210 (void) strlcpy(winreg_sysname, sysname, SYS_NMLN); 211 (void) ndr_svc_register(&winreg_service); 212 } 213 214 static int 215 winreg_s_OpenHKCR(void *arg, ndr_xa_t *mxa) 216 { 217 return (winreg_s_OpenHK(arg, mxa, "HKCR")); 218 } 219 220 static int 221 winreg_s_OpenHKCU(void *arg, ndr_xa_t *mxa) 222 { 223 return (winreg_s_OpenHK(arg, mxa, "HKCU")); 224 } 225 226 static int 227 winreg_s_OpenHKLM(void *arg, ndr_xa_t *mxa) 228 { 229 return (winreg_s_OpenHK(arg, mxa, "HKLM")); 230 } 231 232 static int 233 winreg_s_OpenHKPD(void *arg, ndr_xa_t *mxa) 234 { 235 return (winreg_s_OpenHK(arg, mxa, "HKPD")); 236 } 237 238 static int 239 winreg_s_OpenHKU(void *arg, ndr_xa_t *mxa) 240 { 241 return (winreg_s_OpenHK(arg, mxa, "HKU")); 242 } 243 244 static int 245 winreg_s_OpenHKCC(void *arg, ndr_xa_t *mxa) 246 { 247 return (winreg_s_OpenHK(arg, mxa, "HKCC")); 248 } 249 250 static int 251 winreg_s_OpenHKDD(void *arg, ndr_xa_t *mxa) 252 { 253 return (winreg_s_OpenHK(arg, mxa, "HKDD")); 254 } 255 256 static int 257 winreg_s_OpenHKPT(void *arg, ndr_xa_t *mxa) 258 { 259 return (winreg_s_OpenHK(arg, mxa, "HKPT")); 260 } 261 262 static int 263 winreg_s_OpenHKPN(void *arg, ndr_xa_t *mxa) 264 { 265 return (winreg_s_OpenHK(arg, mxa, "HKPN")); 266 } 267 268 /* 269 * winreg_s_OpenHK 270 * 271 * Common code to open root HKEYs. 272 */ 273 static int 274 winreg_s_OpenHK(void *arg, ndr_xa_t *mxa, const char *hkey) 275 { 276 struct winreg_OpenHKCR *param = arg; 277 ndr_hdid_t *id; 278 char *dupkey; 279 280 if ((dupkey = strdup(hkey)) == NULL) { 281 bzero(¶m->handle, sizeof (winreg_handle_t)); 282 param->status = ERROR_NOT_ENOUGH_MEMORY; 283 return (NDR_DRC_OK); 284 } 285 286 if ((id = ndr_hdalloc(mxa, dupkey)) == NULL) { 287 free(dupkey); 288 bzero(¶m->handle, sizeof (winreg_handle_t)); 289 param->status = ERROR_ACCESS_DENIED; 290 } else { 291 bcopy(id, ¶m->handle, sizeof (winreg_handle_t)); 292 param->status = ERROR_SUCCESS; 293 } 294 295 return (NDR_DRC_OK); 296 } 297 298 /* 299 * winreg_s_Close 300 * 301 * This is a request to close the WINREG interface specified by the 302 * handle. We don't track handles (yet), so just zero out the handle 303 * and return NDR_DRC_OK. Setting the handle to zero appears to be 304 * standard behaviour. 305 */ 306 static int 307 winreg_s_Close(void *arg, ndr_xa_t *mxa) 308 { 309 struct winreg_Close *param = arg; 310 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 311 ndr_handle_t *hd; 312 313 if ((hd = ndr_hdlookup(mxa, id)) != NULL) { 314 free(hd->nh_data); 315 hd->nh_data = NULL; 316 } 317 318 ndr_hdfree(mxa, id); 319 320 bzero(¶m->result_handle, sizeof (winreg_handle_t)); 321 param->status = ERROR_SUCCESS; 322 return (NDR_DRC_OK); 323 } 324 325 /* 326 * winreg_s_CreateKey 327 */ 328 static int 329 winreg_s_CreateKey(void *arg, ndr_xa_t *mxa) 330 { 331 struct winreg_CreateKey *param = arg; 332 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 333 ndr_handle_t *hd; 334 winreg_subkey_t *key; 335 char *subkey; 336 char *dupkey; 337 DWORD *action; 338 339 subkey = (char *)param->subkey.str; 340 341 if (!ndr_is_admin(mxa) || (subkey == NULL)) { 342 bzero(param, sizeof (struct winreg_CreateKey)); 343 param->status = ERROR_ACCESS_DENIED; 344 return (NDR_DRC_OK); 345 } 346 347 hd = ndr_hdlookup(mxa, id); 348 if (hd == NULL) { 349 bzero(param, sizeof (struct winreg_CreateKey)); 350 param->status = ERROR_INVALID_HANDLE; 351 return (NDR_DRC_OK); 352 } 353 354 if ((action = NDR_NEW(mxa, DWORD)) == NULL) { 355 bzero(param, sizeof (struct winreg_CreateKey)); 356 param->status = ERROR_NOT_ENOUGH_MEMORY; 357 return (NDR_DRC_OK); 358 } 359 360 if (list_is_empty(&winreg_keylist.kl_list)) 361 goto new_key; 362 363 /* 364 * Check for an existing key. 365 */ 366 key = list_head(&winreg_keylist.kl_list); 367 do { 368 if (strcasecmp(subkey, key->sk_name) == 0) { 369 bcopy(&key->sk_handle, ¶m->result_handle, 370 sizeof (winreg_handle_t)); 371 *action = WINREG_ACTION_EXISTING_KEY; 372 param->action = action; 373 param->status = ERROR_SUCCESS; 374 return (NDR_DRC_OK); 375 } 376 } while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL); 377 378 new_key: 379 /* 380 * Create a new key. 381 */ 382 if ((dupkey = strdup(subkey)) == NULL) { 383 bzero(param, sizeof (struct winreg_CreateKey)); 384 param->status = ERROR_NOT_ENOUGH_MEMORY; 385 return (NDR_DRC_OK); 386 } 387 388 id = ndr_hdalloc(mxa, dupkey); 389 key = malloc(sizeof (winreg_subkey_t)); 390 391 if ((id == NULL) || (key == NULL)) { 392 free(dupkey); 393 bzero(param, sizeof (struct winreg_CreateKey)); 394 param->status = ERROR_NOT_ENOUGH_MEMORY; 395 return (NDR_DRC_OK); 396 } 397 398 bcopy(id, &key->sk_handle, sizeof (ndr_hdid_t)); 399 (void) strlcpy(key->sk_name, subkey, MAXPATHLEN); 400 key->sk_predefined = B_FALSE; 401 list_insert_tail(&winreg_keylist.kl_list, key); 402 ++winreg_keylist.kl_count; 403 404 bcopy(id, ¶m->result_handle, sizeof (winreg_handle_t)); 405 *action = WINREG_ACTION_NEW_KEY; 406 param->action = action; 407 param->status = ERROR_SUCCESS; 408 return (NDR_DRC_OK); 409 } 410 411 /* 412 * winreg_s_DeleteKey 413 */ 414 static int 415 winreg_s_DeleteKey(void *arg, ndr_xa_t *mxa) 416 { 417 struct winreg_DeleteKey *param = arg; 418 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 419 ndr_handle_t *hd; 420 winreg_subkey_t *key; 421 char *subkey; 422 423 subkey = (char *)param->subkey.str; 424 425 if (!ndr_is_admin(mxa) || (subkey == NULL)) { 426 param->status = ERROR_ACCESS_DENIED; 427 return (NDR_DRC_OK); 428 } 429 430 if ((ndr_hdlookup(mxa, id) == NULL) || 431 list_is_empty(&winreg_keylist.kl_list) || 432 winreg_key_has_subkey(subkey)) { 433 param->status = ERROR_ACCESS_DENIED; 434 return (NDR_DRC_OK); 435 } 436 437 key = list_head(&winreg_keylist.kl_list); 438 do { 439 if (strcasecmp(subkey, key->sk_name) == 0) { 440 if (key->sk_predefined == B_TRUE) { 441 /* Predefined keys cannot be deleted */ 442 break; 443 } 444 445 list_remove(&winreg_keylist.kl_list, key); 446 --winreg_keylist.kl_count; 447 448 hd = ndr_hdlookup(mxa, &key->sk_handle); 449 if (hd != NULL) { 450 free(hd->nh_data); 451 hd->nh_data = NULL; 452 } 453 454 ndr_hdfree(mxa, &key->sk_handle); 455 free(key); 456 param->status = ERROR_SUCCESS; 457 return (NDR_DRC_OK); 458 } 459 } while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL); 460 461 param->status = ERROR_ACCESS_DENIED; 462 return (NDR_DRC_OK); 463 } 464 465 static boolean_t 466 winreg_key_has_subkey(const char *subkey) 467 { 468 winreg_subkey_t *key; 469 int keylen; 470 471 if (list_is_empty(&winreg_keylist.kl_list)) 472 return (B_FALSE); 473 474 keylen = strlen(subkey); 475 476 key = list_head(&winreg_keylist.kl_list); 477 do { 478 if (strncasecmp(subkey, key->sk_name, keylen) == 0) { 479 /* 480 * Potential match. If sk_name is longer than 481 * subkey, then sk_name is a subkey of our key. 482 */ 483 if (keylen < strlen(key->sk_name)) 484 return (B_TRUE); 485 } 486 } while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL); 487 488 return (B_FALSE); 489 } 490 491 static char * 492 winreg_enum_subkey(ndr_xa_t *mxa, const char *subkey, uint32_t index) 493 { 494 winreg_subkey_t *key; 495 char *entry; 496 char *p; 497 int subkeylen; 498 int count = 0; 499 500 if (subkey == NULL) 501 return (NULL); 502 503 if (list_is_empty(&winreg_keylist.kl_list)) 504 return (NULL); 505 506 subkeylen = strlen(subkey); 507 508 for (key = list_head(&winreg_keylist.kl_list); 509 key != NULL; key = list_next(&winreg_keylist.kl_list, key)) { 510 if (strncasecmp(subkey, key->sk_name, subkeylen) == 0) { 511 p = key->sk_name + subkeylen; 512 513 if ((*p != '\\') || (*p == '\0')) { 514 /* 515 * Not the same subkey or an exact match. 516 * We're looking for children of subkey. 517 */ 518 continue; 519 } 520 521 ++p; 522 523 if (count < index) { 524 ++count; 525 continue; 526 } 527 528 if ((entry = NDR_STRDUP(mxa, p)) == NULL) 529 return (NULL); 530 531 if ((p = strchr(entry, '\\')) != NULL) 532 *p = '\0'; 533 534 return (entry); 535 } 536 } 537 538 return (NULL); 539 } 540 541 /* 542 * winreg_s_DeleteValue 543 */ 544 /*ARGSUSED*/ 545 static int 546 winreg_s_DeleteValue(void *arg, ndr_xa_t *mxa) 547 { 548 struct winreg_DeleteValue *param = arg; 549 550 param->status = ERROR_ACCESS_DENIED; 551 return (NDR_DRC_OK); 552 } 553 554 /* 555 * winreg_s_EnumKey 556 */ 557 static int 558 winreg_s_EnumKey(void *arg, ndr_xa_t *mxa) 559 { 560 struct winreg_EnumKey *param = arg; 561 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 562 ndr_handle_t *hd; 563 char *subkey; 564 char *name = NULL; 565 566 if ((hd = ndr_hdlookup(mxa, id)) != NULL) 567 name = hd->nh_data; 568 569 if (hd == NULL || name == NULL) { 570 bzero(param, sizeof (struct winreg_EnumKey)); 571 param->status = ERROR_NO_MORE_ITEMS; 572 return (NDR_DRC_OK); 573 } 574 575 subkey = winreg_enum_subkey(mxa, name, param->index); 576 if (subkey == NULL) { 577 bzero(param, sizeof (struct winreg_EnumKey)); 578 param->status = ERROR_NO_MORE_ITEMS; 579 return (NDR_DRC_OK); 580 } 581 582 if (NDR_MSTRING(mxa, subkey, (ndr_mstring_t *)¶m->name_out) == -1) { 583 bzero(param, sizeof (struct winreg_EnumKey)); 584 param->status = ERROR_NOT_ENOUGH_MEMORY; 585 return (NDR_DRC_OK); 586 } 587 /* 588 * This request requires that the length includes the null. 589 */ 590 param->name_out.length = param->name_out.allosize; 591 592 param->status = ERROR_SUCCESS; 593 return (NDR_DRC_OK); 594 } 595 596 /* 597 * winreg_s_EnumValue 598 */ 599 static int 600 winreg_s_EnumValue(void *arg, ndr_xa_t *mxa) 601 { 602 struct winreg_EnumValue *param = arg; 603 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 604 605 if (ndr_hdlookup(mxa, id) == NULL) { 606 bzero(param, sizeof (struct winreg_EnumValue)); 607 param->status = ERROR_NO_MORE_ITEMS; 608 return (NDR_DRC_OK); 609 } 610 611 bzero(param, sizeof (struct winreg_EnumValue)); 612 param->status = ERROR_NO_MORE_ITEMS; 613 return (NDR_DRC_OK); 614 } 615 616 /* 617 * winreg_s_FlushKey 618 * 619 * Flush the attributes associated with the specified open key to disk. 620 */ 621 static int 622 winreg_s_FlushKey(void *arg, ndr_xa_t *mxa) 623 { 624 struct winreg_FlushKey *param = arg; 625 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 626 627 if (ndr_hdlookup(mxa, id) == NULL) 628 param->status = ERROR_INVALID_HANDLE; 629 else 630 param->status = ERROR_SUCCESS; 631 632 return (NDR_DRC_OK); 633 } 634 635 /* 636 * winreg_s_GetKeySec 637 */ 638 static int 639 winreg_s_GetKeySec(void *arg, ndr_xa_t *mxa) 640 { 641 static struct winreg_secdesc error_sd; 642 struct winreg_GetKeySec *param = arg; 643 struct winreg_value *sd_buf; 644 smb_sd_t sd; 645 uint32_t sd_len; 646 uint32_t status; 647 648 bzero(&sd, sizeof (smb_sd_t)); 649 650 if ((status = winreg_sd_format(&sd)) != ERROR_SUCCESS) 651 goto winreg_getkeysec_error; 652 653 sd_len = smb_sd_len(&sd, SMB_ALL_SECINFO); 654 sd_buf = NDR_MALLOC(mxa, sd_len + sizeof (struct winreg_value)); 655 656 param->sd = NDR_MALLOC(mxa, sizeof (struct winreg_secdesc)); 657 if ((param->sd == NULL) || (sd_buf == NULL)) { 658 status = ERROR_NOT_ENOUGH_MEMORY; 659 goto winreg_getkeysec_error; 660 } 661 662 param->sd->sd_len = sd_len; 663 param->sd->sd_size = sd_len; 664 param->sd->sd_buf = sd_buf; 665 666 sd_buf->vc_first_is = 0; 667 sd_buf->vc_length_is = sd_len; 668 param->status = srvsvc_sd_set_relative(&sd, sd_buf->value); 669 670 smb_sd_term(&sd); 671 return (NDR_DRC_OK); 672 673 winreg_getkeysec_error: 674 smb_sd_term(&sd); 675 bzero(param, sizeof (struct winreg_GetKeySec)); 676 param->sd = &error_sd; 677 param->status = status; 678 return (NDR_DRC_OK); 679 } 680 681 static uint32_t 682 winreg_sd_format(smb_sd_t *sd) 683 { 684 smb_fssd_t fs_sd; 685 acl_t *acl; 686 uint32_t status = ERROR_SUCCESS; 687 688 if (acl_fromtext("owner@:rwxpdDaARWcCos::allow", &acl) != 0) 689 return (ERROR_NOT_ENOUGH_MEMORY); 690 691 smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR); 692 fs_sd.sd_uid = 0; 693 fs_sd.sd_gid = 0; 694 fs_sd.sd_zdacl = acl; 695 fs_sd.sd_zsacl = NULL; 696 697 if (smb_sd_fromfs(&fs_sd, sd) != NT_STATUS_SUCCESS) 698 status = ERROR_ACCESS_DENIED; 699 smb_fssd_term(&fs_sd); 700 return (status); 701 } 702 703 /* 704 * winreg_s_NotifyChange 705 */ 706 static int 707 winreg_s_NotifyChange(void *arg, ndr_xa_t *mxa) 708 { 709 struct winreg_NotifyChange *param = arg; 710 711 if (ndr_is_admin(mxa)) 712 param->status = ERROR_SUCCESS; 713 else 714 param->status = ERROR_ACCESS_DENIED; 715 716 return (NDR_DRC_OK); 717 } 718 719 /* 720 * winreg_s_OpenKey 721 * 722 * This is a request to open a windows registry key. 723 * If we recognize the key, we return a handle. 724 * 725 * Returns: 726 * ERROR_SUCCESS Valid handle returned. 727 * ERROR_FILE_NOT_FOUND No key or unable to allocate a handle. 728 */ 729 static int 730 winreg_s_OpenKey(void *arg, ndr_xa_t *mxa) 731 { 732 struct winreg_OpenKey *param = arg; 733 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 734 ndr_handle_t *hd; 735 char *subkey = (char *)param->name.str; 736 winreg_subkey_t *key; 737 char *dupkey; 738 739 if (subkey == NULL || *subkey == '\0') { 740 if ((hd = ndr_hdlookup(mxa, id)) != NULL) 741 subkey = hd->nh_data; 742 } 743 744 id = NULL; 745 746 if (subkey == NULL || list_is_empty(&winreg_keylist.kl_list)) { 747 bzero(¶m->result_handle, sizeof (winreg_handle_t)); 748 param->status = ERROR_FILE_NOT_FOUND; 749 return (NDR_DRC_OK); 750 } 751 752 key = list_head(&winreg_keylist.kl_list); 753 do { 754 if (strcasecmp(subkey, key->sk_name) == 0) { 755 if (key->sk_predefined == B_TRUE) { 756 if ((dupkey = strdup(subkey)) == NULL) 757 break; 758 759 id = ndr_hdalloc(mxa, dupkey); 760 if (id == NULL) 761 free(dupkey); 762 } else { 763 id = &key->sk_handle; 764 } 765 766 if (id == NULL) 767 break; 768 769 bcopy(id, ¶m->result_handle, 770 sizeof (winreg_handle_t)); 771 param->status = ERROR_SUCCESS; 772 return (NDR_DRC_OK); 773 } 774 } while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL); 775 776 bzero(¶m->result_handle, sizeof (winreg_handle_t)); 777 param->status = ERROR_FILE_NOT_FOUND; 778 return (NDR_DRC_OK); 779 } 780 781 /* 782 * winreg_s_QueryKey 783 */ 784 /*ARGSUSED*/ 785 static int 786 winreg_s_QueryKey(void *arg, ndr_xa_t *mxa) 787 { 788 struct winreg_QueryKey *param = arg; 789 int rc; 790 winreg_string_t *name; 791 792 name = (winreg_string_t *)¶m->name; 793 bzero(param, sizeof (struct winreg_QueryKey)); 794 if ((name = NDR_NEW(mxa, winreg_string_t)) != NULL) 795 rc = NDR_MSTRING(mxa, "", (ndr_mstring_t *)name); 796 797 if ((name == NULL) || (rc != 0)) { 798 bzero(param, sizeof (struct winreg_QueryKey)); 799 param->status = ERROR_NOT_ENOUGH_MEMORY; 800 return (NDR_DRC_OK); 801 } 802 803 param->status = ERROR_SUCCESS; 804 return (NDR_DRC_OK); 805 } 806 807 /* 808 * winreg_s_QueryValue 809 * 810 * This is a request to get the value associated with a specified name. 811 * 812 * Returns: 813 * ERROR_SUCCESS Value returned. 814 * ERROR_FILE_NOT_FOUND PrimaryModule is not supported. 815 * ERROR_CANTREAD No such name or memory problem. 816 */ 817 static int 818 winreg_s_QueryValue(void *arg, ndr_xa_t *mxa) 819 { 820 struct winreg_QueryValue *param = arg; 821 struct winreg_value *pv; 822 char *name; 823 char *value; 824 DWORD slen; 825 DWORD msize; 826 827 name = (char *)param->value_name.str; 828 829 if (strcasecmp(name, "PrimaryModule") == 0) { 830 param->status = ERROR_FILE_NOT_FOUND; 831 return (NDR_DRC_OK); 832 } 833 834 if ((value = winreg_lookup_value(name)) == NULL) { 835 param->status = ERROR_CANTREAD; 836 return (NDR_DRC_OK); 837 } 838 839 slen = smb_wcequiv_strlen(value) + sizeof (smb_wchar_t); 840 msize = sizeof (struct winreg_value) + slen; 841 842 param->value = (struct winreg_value *)NDR_MALLOC(mxa, msize); 843 param->type = NDR_NEW(mxa, DWORD); 844 param->value_size = NDR_NEW(mxa, DWORD); 845 param->value_size_total = NDR_NEW(mxa, DWORD); 846 847 if (param->value == NULL || param->type == NULL || 848 param->value_size == NULL || param->value_size_total == NULL) { 849 param->status = ERROR_CANTREAD; 850 return (NDR_DRC_OK); 851 } 852 853 bzero(param->value, msize); 854 pv = param->value; 855 pv->vc_first_is = 0; 856 pv->vc_length_is = slen; 857 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 858 (void) ndr_mbstowcs(NULL, (smb_wchar_t *)pv->value, value, slen); 859 860 *param->type = 1; 861 *param->value_size = slen; 862 *param->value_size_total = slen; 863 864 param->status = ERROR_SUCCESS; 865 return (NDR_DRC_OK); 866 } 867 868 /* 869 * Lookup a name in the registry and return the associated value. 870 * Our registry is a case-insensitive, name-value pair table. 871 * 872 * Windows ProductType: WinNT, ServerNT, LanmanNT. 873 * Windows NT4.0 workstation: WinNT 874 * Windows NT4.0 server: ServerNT 875 * 876 * If LanmanNT is used here, Windows 2000 sends LsarQueryInfoPolicy 877 * with info level 6, which we don't support. If we use ServerNT 878 * (as reported by NT4.0 Server) Windows 2000 send requests for 879 * levels 3 and 5, which are support. 880 * 881 * On success, returns a pointer to the value. Otherwise returns 882 * a null pointer. 883 */ 884 static char * 885 winreg_lookup_value(const char *name) 886 { 887 static struct registry { 888 char *name; 889 char *value; 890 } registry[] = { 891 { "CurrentVersion", "4.0" }, 892 { "ProductType", "ServerNT" }, 893 { "Sources", NULL } /* product name */ 894 }; 895 896 int i; 897 898 for (i = 0; i < sizeof (registry)/sizeof (registry[0]); ++i) { 899 if (strcasecmp(registry[i].name, name) == 0) { 900 if (registry[i].value == NULL) 901 return (winreg_sysname); 902 else 903 return (registry[i].value); 904 } 905 } 906 907 return (NULL); 908 } 909 910 /* 911 * winreg_s_SetKeySec 912 */ 913 /*ARGSUSED*/ 914 static int 915 winreg_s_SetKeySec(void *arg, ndr_xa_t *mxa) 916 { 917 struct winreg_SetKeySec *param = arg; 918 919 param->status = ERROR_ACCESS_DENIED; 920 return (NDR_DRC_OK); 921 } 922 923 /* 924 * winreg_s_CreateValue 925 */ 926 /*ARGSUSED*/ 927 static int 928 winreg_s_CreateValue(void *arg, ndr_xa_t *mxa) 929 { 930 struct winreg_CreateValue *param = arg; 931 932 param->status = ERROR_ACCESS_DENIED; 933 return (NDR_DRC_OK); 934 } 935 936 /* 937 * winreg_s_Shutdown 938 * 939 * Attempt to shutdown or reboot the system: access denied. 940 */ 941 /*ARGSUSED*/ 942 static int 943 winreg_s_Shutdown(void *arg, ndr_xa_t *mxa) 944 { 945 struct winreg_Shutdown *param = arg; 946 947 param->status = ERROR_ACCESS_DENIED; 948 return (NDR_DRC_OK); 949 } 950 951 /* 952 * winreg_s_AbortShutdown 953 * 954 * Abort a shutdown request. 955 */ 956 static int 957 winreg_s_AbortShutdown(void *arg, ndr_xa_t *mxa) 958 { 959 struct winreg_AbortShutdown *param = arg; 960 961 if (ndr_is_admin(mxa)) 962 param->status = ERROR_SUCCESS; 963 else 964 param->status = ERROR_ACCESS_DENIED; 965 966 return (NDR_DRC_OK); 967 } 968 969 /* 970 * winreg_s_GetVersion 971 * 972 * Return the windows registry version. The current version is 5. 973 * This call is usually made prior to enumerating or querying registry 974 * keys or values. 975 */ 976 /*ARGSUSED*/ 977 static int 978 winreg_s_GetVersion(void *arg, ndr_xa_t *mxa) 979 { 980 struct winreg_GetVersion *param = arg; 981 982 param->version = 5; 983 param->status = ERROR_SUCCESS; 984 return (NDR_DRC_OK); 985 } 986