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 struct winreg_GetKeySec *param = arg; 642 struct winreg_value *sd_buf; 643 smb_sd_t sd; 644 uint32_t sd_len; 645 uint32_t status; 646 647 bzero(&sd, sizeof (smb_sd_t)); 648 649 if ((status = winreg_sd_format(&sd)) != ERROR_SUCCESS) 650 goto winreg_getkeysec_error; 651 652 sd_len = smb_sd_len(&sd, SMB_ALL_SECINFO); 653 654 param->sd = NDR_MALLOC(mxa, sizeof (struct winreg_secdesc)); 655 if (param->sd == NULL) { 656 status = ERROR_NOT_ENOUGH_MEMORY; 657 goto winreg_getkeysec_error; 658 } 659 660 param->sd->sd_len = sd_len; 661 param->sd->sd_size = sd_len; 662 663 sd_buf = NDR_MALLOC(mxa, sd_len + sizeof (struct winreg_value)); 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->status = status; 677 return (NDR_DRC_OK); 678 } 679 680 static uint32_t 681 winreg_sd_format(smb_sd_t *sd) 682 { 683 smb_fssd_t fs_sd; 684 acl_t *acl; 685 uint32_t status = ERROR_SUCCESS; 686 687 if (acl_fromtext("owner@:rwxpdDaARWcCos::allow", &acl) != 0) 688 return (ERROR_NOT_ENOUGH_MEMORY); 689 690 smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR); 691 fs_sd.sd_uid = 0; 692 fs_sd.sd_gid = 0; 693 fs_sd.sd_zdacl = acl; 694 fs_sd.sd_zsacl = NULL; 695 696 if (smb_sd_fromfs(&fs_sd, sd) != NT_STATUS_SUCCESS) 697 status = ERROR_ACCESS_DENIED; 698 smb_fssd_term(&fs_sd); 699 return (status); 700 } 701 702 /* 703 * winreg_s_NotifyChange 704 */ 705 static int 706 winreg_s_NotifyChange(void *arg, ndr_xa_t *mxa) 707 { 708 struct winreg_NotifyChange *param = arg; 709 710 if (ndr_is_admin(mxa)) 711 param->status = ERROR_SUCCESS; 712 else 713 param->status = ERROR_ACCESS_DENIED; 714 715 return (NDR_DRC_OK); 716 } 717 718 /* 719 * winreg_s_OpenKey 720 * 721 * This is a request to open a windows registry key. 722 * If we recognize the key, we return a handle. 723 * 724 * Returns: 725 * ERROR_SUCCESS Valid handle returned. 726 * ERROR_FILE_NOT_FOUND No key or unable to allocate a handle. 727 */ 728 static int 729 winreg_s_OpenKey(void *arg, ndr_xa_t *mxa) 730 { 731 struct winreg_OpenKey *param = arg; 732 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 733 ndr_handle_t *hd; 734 char *subkey = (char *)param->name.str; 735 winreg_subkey_t *key; 736 char *dupkey; 737 738 if (subkey == NULL || *subkey == '\0') { 739 if ((hd = ndr_hdlookup(mxa, id)) != NULL) 740 subkey = hd->nh_data; 741 } 742 743 id = NULL; 744 745 if (subkey == NULL || list_is_empty(&winreg_keylist.kl_list)) { 746 bzero(¶m->result_handle, sizeof (winreg_handle_t)); 747 param->status = ERROR_FILE_NOT_FOUND; 748 return (NDR_DRC_OK); 749 } 750 751 key = list_head(&winreg_keylist.kl_list); 752 do { 753 if (strcasecmp(subkey, key->sk_name) == 0) { 754 if (key->sk_predefined == B_TRUE) { 755 if ((dupkey = strdup(subkey)) == NULL) 756 break; 757 758 id = ndr_hdalloc(mxa, dupkey); 759 if (id == NULL) 760 free(dupkey); 761 } else { 762 id = &key->sk_handle; 763 } 764 765 if (id == NULL) 766 break; 767 768 bcopy(id, ¶m->result_handle, 769 sizeof (winreg_handle_t)); 770 param->status = ERROR_SUCCESS; 771 return (NDR_DRC_OK); 772 } 773 } while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL); 774 775 bzero(¶m->result_handle, sizeof (winreg_handle_t)); 776 param->status = ERROR_FILE_NOT_FOUND; 777 return (NDR_DRC_OK); 778 } 779 780 /* 781 * winreg_s_QueryKey 782 */ 783 /*ARGSUSED*/ 784 static int 785 winreg_s_QueryKey(void *arg, ndr_xa_t *mxa) 786 { 787 struct winreg_QueryKey *param = arg; 788 int rc; 789 winreg_string_t *name; 790 791 name = (winreg_string_t *)¶m->name; 792 bzero(param, sizeof (struct winreg_QueryKey)); 793 if ((name = NDR_NEW(mxa, winreg_string_t)) != NULL) 794 rc = NDR_MSTRING(mxa, "", (ndr_mstring_t *)name); 795 796 if ((name == NULL) || (rc != 0)) { 797 bzero(param, sizeof (struct winreg_QueryKey)); 798 param->status = ERROR_NOT_ENOUGH_MEMORY; 799 return (NDR_DRC_OK); 800 } 801 802 param->status = ERROR_SUCCESS; 803 return (NDR_DRC_OK); 804 } 805 806 /* 807 * winreg_s_QueryValue 808 * 809 * This is a request to get the value associated with a specified name. 810 * 811 * Returns: 812 * ERROR_SUCCESS Value returned. 813 * ERROR_FILE_NOT_FOUND PrimaryModule is not supported. 814 * ERROR_CANTREAD No such name or memory problem. 815 */ 816 static int 817 winreg_s_QueryValue(void *arg, ndr_xa_t *mxa) 818 { 819 struct winreg_QueryValue *param = arg; 820 struct winreg_value *pv; 821 char *name; 822 char *value; 823 DWORD slen; 824 DWORD msize; 825 826 name = (char *)param->value_name.str; 827 828 if (strcasecmp(name, "PrimaryModule") == 0) { 829 param->status = ERROR_FILE_NOT_FOUND; 830 return (NDR_DRC_OK); 831 } 832 833 if ((value = winreg_lookup_value(name)) == NULL) { 834 param->status = ERROR_CANTREAD; 835 return (NDR_DRC_OK); 836 } 837 838 slen = smb_wcequiv_strlen(value) + sizeof (smb_wchar_t); 839 msize = sizeof (struct winreg_value) + slen; 840 841 param->value = (struct winreg_value *)NDR_MALLOC(mxa, msize); 842 param->type = NDR_NEW(mxa, DWORD); 843 param->value_size = NDR_NEW(mxa, DWORD); 844 param->value_size_total = NDR_NEW(mxa, DWORD); 845 846 if (param->value == NULL || param->type == NULL || 847 param->value_size == NULL || param->value_size_total == NULL) { 848 param->status = ERROR_CANTREAD; 849 return (NDR_DRC_OK); 850 } 851 852 bzero(param->value, msize); 853 pv = param->value; 854 pv->vc_first_is = 0; 855 pv->vc_length_is = slen; 856 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 857 (void) ndr_mbstowcs(NULL, (smb_wchar_t *)pv->value, value, slen); 858 859 *param->type = 1; 860 *param->value_size = slen; 861 *param->value_size_total = slen; 862 863 param->status = ERROR_SUCCESS; 864 return (NDR_DRC_OK); 865 } 866 867 /* 868 * Lookup a name in the registry and return the associated value. 869 * Our registry is a case-insensitive, name-value pair table. 870 * 871 * Windows ProductType: WinNT, ServerNT, LanmanNT. 872 * Windows NT4.0 workstation: WinNT 873 * Windows NT4.0 server: ServerNT 874 * 875 * If LanmanNT is used here, Windows 2000 sends LsarQueryInfoPolicy 876 * with info level 6, which we don't support. If we use ServerNT 877 * (as reported by NT4.0 Server) Windows 2000 send requests for 878 * levels 3 and 5, which are support. 879 * 880 * On success, returns a pointer to the value. Otherwise returns 881 * a null pointer. 882 */ 883 static char * 884 winreg_lookup_value(const char *name) 885 { 886 static struct registry { 887 char *name; 888 char *value; 889 } registry[] = { 890 { "CurrentVersion", "4.0" }, 891 { "ProductType", "ServerNT" }, 892 { "Sources", NULL } /* product name */ 893 }; 894 895 int i; 896 897 for (i = 0; i < sizeof (registry)/sizeof (registry[0]); ++i) { 898 if (strcasecmp(registry[i].name, name) == 0) { 899 if (registry[i].value == NULL) 900 return (winreg_sysname); 901 else 902 return (registry[i].value); 903 } 904 } 905 906 return (NULL); 907 } 908 909 /* 910 * winreg_s_SetKeySec 911 */ 912 /*ARGSUSED*/ 913 static int 914 winreg_s_SetKeySec(void *arg, ndr_xa_t *mxa) 915 { 916 struct winreg_SetKeySec *param = arg; 917 918 param->status = ERROR_ACCESS_DENIED; 919 return (NDR_DRC_OK); 920 } 921 922 /* 923 * winreg_s_CreateValue 924 */ 925 /*ARGSUSED*/ 926 static int 927 winreg_s_CreateValue(void *arg, ndr_xa_t *mxa) 928 { 929 struct winreg_CreateValue *param = arg; 930 931 param->status = ERROR_ACCESS_DENIED; 932 return (NDR_DRC_OK); 933 } 934 935 /* 936 * winreg_s_Shutdown 937 * 938 * Attempt to shutdown or reboot the system: access denied. 939 */ 940 /*ARGSUSED*/ 941 static int 942 winreg_s_Shutdown(void *arg, ndr_xa_t *mxa) 943 { 944 struct winreg_Shutdown *param = arg; 945 946 param->status = ERROR_ACCESS_DENIED; 947 return (NDR_DRC_OK); 948 } 949 950 /* 951 * winreg_s_AbortShutdown 952 * 953 * Abort a shutdown request. 954 */ 955 static int 956 winreg_s_AbortShutdown(void *arg, ndr_xa_t *mxa) 957 { 958 struct winreg_AbortShutdown *param = arg; 959 960 if (ndr_is_admin(mxa)) 961 param->status = ERROR_SUCCESS; 962 else 963 param->status = ERROR_ACCESS_DENIED; 964 965 return (NDR_DRC_OK); 966 } 967 968 /* 969 * winreg_s_GetVersion 970 * 971 * Return the windows registry version. The current version is 5. 972 * This call is usually made prior to enumerating or querying registry 973 * keys or values. 974 */ 975 /*ARGSUSED*/ 976 static int 977 winreg_s_GetVersion(void *arg, ndr_xa_t *mxa) 978 { 979 struct winreg_GetVersion *param = arg; 980 981 param->version = 5; 982 param->status = ERROR_SUCCESS; 983 return (NDR_DRC_OK); 984 } 985