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