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