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