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