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