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