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