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