/src/samba/source3/registry/reg_backend_db.c
Line | Count | Source |
1 | | /* |
2 | | * Unix SMB/CIFS implementation. |
3 | | * Virtual Windows Registry Layer |
4 | | * Copyright (C) Gerald Carter 2002-2005 |
5 | | * Copyright (C) Michael Adam 2007-2011 |
6 | | * Copyright (C) Gregor Beck 2011 |
7 | | * |
8 | | * This program is free software; you can redistribute it and/or modify |
9 | | * it under the terms of the GNU General Public License as published by |
10 | | * the Free Software Foundation; either version 3 of the License, or |
11 | | * (at your option) any later version. |
12 | | * |
13 | | * This program is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU General Public License |
19 | | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
20 | | */ |
21 | | |
22 | | /* Implementation of internal registry database functions. */ |
23 | | |
24 | | #include "includes.h" |
25 | | #include "system/filesys.h" |
26 | | #include "registry.h" |
27 | | #include "reg_db.h" |
28 | | #include "reg_util_internal.h" |
29 | | #include "reg_parse_internal.h" |
30 | | #include "reg_backend_db.h" |
31 | | #include "reg_objects.h" |
32 | | #include "nt_printing.h" |
33 | | #include "util_tdb.h" |
34 | | #include "dbwrap/dbwrap.h" |
35 | | #include "dbwrap/dbwrap_open.h" |
36 | | #include "../libcli/security/secdesc.h" |
37 | | |
38 | | #undef DBGC_CLASS |
39 | 0 | #define DBGC_CLASS DBGC_REGISTRY |
40 | | |
41 | 0 | #define REGDB_VERSION_KEYNAME "INFO/version" |
42 | | |
43 | | static struct db_context *regdb = NULL; |
44 | | static int regdb_refcount; |
45 | | |
46 | | static bool regdb_key_exists(struct db_context *db, const char *key); |
47 | | static WERROR regdb_fetch_keys_internal(struct db_context *db, const char *key, |
48 | | struct regsubkey_ctr *ctr); |
49 | | static bool regdb_store_keys_internal(struct db_context *db, const char *key, |
50 | | struct regsubkey_ctr *ctr); |
51 | | static int regdb_fetch_values_internal(struct db_context *db, const char* key, |
52 | | struct regval_ctr *values); |
53 | | static NTSTATUS regdb_store_values_internal(struct db_context *db, const char *key, |
54 | | struct regval_ctr *values); |
55 | | static WERROR regdb_store_subkey_list(struct db_context *db, const char *parent, |
56 | | const char *key); |
57 | | |
58 | | static WERROR regdb_create_basekey(struct db_context *db, const char *key); |
59 | | static WERROR regdb_create_subkey_internal(struct db_context *db, |
60 | | const char *key, |
61 | | const char *subkey); |
62 | | |
63 | | |
64 | | struct regdb_trans_ctx { |
65 | | NTSTATUS (*action)(struct db_context *, void *); |
66 | | void *private_data; |
67 | | }; |
68 | | |
69 | | static NTSTATUS regdb_trans_do_action(struct db_context *db, void *private_data) |
70 | 0 | { |
71 | 0 | NTSTATUS status; |
72 | 0 | int32_t version_id; |
73 | 0 | struct regdb_trans_ctx *ctx = (struct regdb_trans_ctx *)private_data; |
74 | |
|
75 | 0 | status = dbwrap_fetch_int32_bystring(db, REGDB_VERSION_KEYNAME, |
76 | 0 | &version_id); |
77 | |
|
78 | 0 | if (!NT_STATUS_IS_OK(status)) { |
79 | 0 | DEBUG(0, ("ERROR: could not fetch registry db version: %s. " |
80 | 0 | "Denying access.\n", nt_errstr(status))); |
81 | 0 | return NT_STATUS_ACCESS_DENIED; |
82 | 0 | } |
83 | | |
84 | 0 | if (version_id != REGDB_CODE_VERSION) { |
85 | 0 | DEBUG(0, ("ERROR: changed registry version %d found while " |
86 | 0 | "trying to write to the registry. Version %d " |
87 | 0 | "expected. Denying access.\n", |
88 | 0 | version_id, REGDB_CODE_VERSION)); |
89 | 0 | return NT_STATUS_ACCESS_DENIED; |
90 | 0 | } |
91 | | |
92 | 0 | status = ctx->action(db, ctx->private_data); |
93 | 0 | return status; |
94 | 0 | } |
95 | | |
96 | | static WERROR regdb_trans_do(struct db_context *db, |
97 | | NTSTATUS (*action)(struct db_context *, void *), |
98 | | void *private_data) |
99 | 0 | { |
100 | 0 | NTSTATUS status; |
101 | 0 | struct regdb_trans_ctx ctx; |
102 | | |
103 | |
|
104 | 0 | ctx.action = action; |
105 | 0 | ctx.private_data = private_data; |
106 | |
|
107 | 0 | status = dbwrap_trans_do(db, regdb_trans_do_action, &ctx); |
108 | |
|
109 | 0 | return ntstatus_to_werror(status); |
110 | 0 | } |
111 | | |
112 | | /* List the deepest path into the registry. All part components will be created.*/ |
113 | | |
114 | | /* If you want to have a part of the path controlled by the tdb and part by |
115 | | a virtual registry db (e.g. printing), then you have to list the deepest path. |
116 | | For example,"HKLM/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Print" |
117 | | allows the reg_db backend to handle everything up to |
118 | | "HKLM/SOFTWARE/Microsoft/Windows NT/CurrentVersion" and then we'll hook |
119 | | the reg_printing backend onto the last component of the path (see |
120 | | KEY_PRINTING_2K in include/rpc_reg.h) --jerry */ |
121 | | |
122 | | static const char *builtin_registry_paths[] = { |
123 | | KEY_PRINTING_2K, |
124 | | KEY_PCC, |
125 | | KEY_PRINTING_PORTS, |
126 | | KEY_PRINTING, |
127 | | KEY_PRINTING "\\Forms", |
128 | | KEY_PRINTING "\\Printers", |
129 | | KEY_PRINTING "\\Environments\\Windows NT x86\\Print Processors\\winprint", |
130 | | KEY_PRINTING "\\Environments\\Windows x64\\Print Processors\\winprint", |
131 | | KEY_SHARES, |
132 | | KEY_EVENTLOG, |
133 | | KEY_SMBCONF, |
134 | | KEY_PERFLIB, |
135 | | KEY_PERFLIB_009, |
136 | | KEY_GROUP_POLICY, |
137 | | KEY_SAMBA_GROUP_POLICY, |
138 | | KEY_GP_MACHINE_POLICY, |
139 | | KEY_GP_MACHINE_WIN_POLICY, |
140 | | KEY_HKCU, |
141 | | KEY_GP_USER_POLICY, |
142 | | KEY_GP_USER_WIN_POLICY, |
143 | | "HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\GPExtensions", |
144 | | "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors", |
145 | | KEY_PROD_OPTIONS, |
146 | | "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\DefaultUserConfiguration", |
147 | | KEY_TCPIP_PARAMS, |
148 | | KEY_NETLOGON_PARAMS, |
149 | | KEY_HKU, |
150 | | KEY_HKCR, |
151 | | KEY_HKPD, |
152 | | KEY_HKPT, |
153 | | NULL }; |
154 | | |
155 | | struct builtin_regkey_value { |
156 | | const char *path; |
157 | | const char *valuename; |
158 | | uint32_t type; |
159 | | union { |
160 | | const char *string; |
161 | | uint32_t dw_value; |
162 | | } data; |
163 | | }; |
164 | | |
165 | | static struct builtin_regkey_value builtin_registry_values[] = { |
166 | | { KEY_PRINTING_PORTS, |
167 | | SAMBA_PRINTER_PORT_NAME, REG_SZ, { "" } }, |
168 | | { KEY_PRINTING_2K, |
169 | | "DefaultSpoolDirectory", REG_SZ, { "C:\\Windows\\System32\\Spool\\Printers" } }, |
170 | | { KEY_EVENTLOG, |
171 | | "DisplayName", REG_SZ, { "Event Log" } }, |
172 | | { KEY_EVENTLOG, |
173 | | "ErrorControl", REG_DWORD, { (char*)0x00000001 } }, |
174 | | { NULL, NULL, 0, { NULL } } |
175 | | }; |
176 | | |
177 | | static WERROR create_key_recursive(struct db_context *db, |
178 | | char *path, |
179 | | const char *subkey) |
180 | 0 | { |
181 | 0 | WERROR werr; |
182 | 0 | char *p; |
183 | |
|
184 | 0 | if (subkey == NULL) { |
185 | 0 | return WERR_INVALID_PARAMETER; |
186 | 0 | } |
187 | | |
188 | 0 | if (path == NULL) { |
189 | 0 | return regdb_create_basekey(db, subkey); |
190 | 0 | } |
191 | | |
192 | 0 | p = strrchr_m(path, '\\'); |
193 | |
|
194 | 0 | if (p == NULL) { |
195 | 0 | werr = create_key_recursive(db, NULL, path); |
196 | 0 | } else { |
197 | 0 | *p = '\0'; |
198 | 0 | werr = create_key_recursive(db, path, p+1); |
199 | 0 | *p = '\\'; |
200 | 0 | } |
201 | |
|
202 | 0 | if (!W_ERROR_IS_OK(werr)) { |
203 | 0 | goto done; |
204 | 0 | } |
205 | | |
206 | 0 | werr = regdb_create_subkey_internal(db, path, subkey); |
207 | |
|
208 | 0 | done: |
209 | 0 | return werr; |
210 | 0 | } |
211 | | |
212 | | /** |
213 | | * Initialize a key in the registry: |
214 | | * create each component key of the specified path. |
215 | | */ |
216 | | static WERROR init_registry_key_internal(struct db_context *db, |
217 | | const char *add_path) |
218 | 0 | { |
219 | 0 | char *subkey, *key; |
220 | 0 | WERROR werr; |
221 | 0 | TALLOC_CTX *frame = talloc_stackframe(); |
222 | |
|
223 | 0 | if (add_path == NULL) { |
224 | 0 | werr = WERR_INVALID_PARAMETER; |
225 | 0 | goto done; |
226 | 0 | } |
227 | | |
228 | 0 | key = talloc_strdup(frame, add_path); |
229 | |
|
230 | 0 | subkey = strrchr_m(key, '\\'); |
231 | 0 | if (subkey == NULL) { |
232 | 0 | subkey = key; |
233 | 0 | key = NULL; |
234 | 0 | } else { |
235 | 0 | *subkey = '\0'; |
236 | 0 | subkey++; |
237 | 0 | } |
238 | |
|
239 | 0 | werr = create_key_recursive(db, key, subkey); |
240 | |
|
241 | 0 | done: |
242 | 0 | talloc_free(frame); |
243 | 0 | return werr; |
244 | 0 | } |
245 | | |
246 | | struct init_registry_key_context { |
247 | | const char *add_path; |
248 | | }; |
249 | | |
250 | | static NTSTATUS init_registry_key_action(struct db_context *db, |
251 | | void *private_data) |
252 | 0 | { |
253 | 0 | struct init_registry_key_context *init_ctx = |
254 | 0 | (struct init_registry_key_context *)private_data; |
255 | |
|
256 | 0 | return werror_to_ntstatus(init_registry_key_internal( |
257 | 0 | db, init_ctx->add_path)); |
258 | 0 | } |
259 | | |
260 | | /** |
261 | | * Initialize a key in the registry: |
262 | | * create each component key of the specified path, |
263 | | * wrapped in one db transaction. |
264 | | */ |
265 | | WERROR init_registry_key(const char *add_path) |
266 | 0 | { |
267 | 0 | struct init_registry_key_context init_ctx; |
268 | |
|
269 | 0 | if (regdb_key_exists(regdb, add_path)) { |
270 | 0 | return WERR_OK; |
271 | 0 | } |
272 | | |
273 | 0 | init_ctx.add_path = add_path; |
274 | |
|
275 | 0 | return regdb_trans_do(regdb, |
276 | 0 | init_registry_key_action, |
277 | 0 | &init_ctx); |
278 | 0 | } |
279 | | |
280 | | /*********************************************************************** |
281 | | Open the registry data in the tdb |
282 | | ***********************************************************************/ |
283 | | |
284 | | static void regdb_ctr_add_value(struct regval_ctr *ctr, |
285 | | struct builtin_regkey_value *value) |
286 | 0 | { |
287 | 0 | switch(value->type) { |
288 | 0 | case REG_DWORD: |
289 | 0 | regval_ctr_addvalue(ctr, value->valuename, REG_DWORD, |
290 | 0 | (uint8_t *)&value->data.dw_value, |
291 | 0 | sizeof(uint32_t)); |
292 | 0 | break; |
293 | | |
294 | 0 | case REG_SZ: |
295 | 0 | regval_ctr_addvalue_sz(ctr, value->valuename, |
296 | 0 | value->data.string); |
297 | 0 | break; |
298 | | |
299 | 0 | default: |
300 | 0 | DEBUG(0, ("regdb_ctr_add_value: invalid value type in " |
301 | 0 | "registry values [%d]\n", value->type)); |
302 | 0 | } |
303 | 0 | } |
304 | | |
305 | | static NTSTATUS init_registry_data_action(struct db_context *db, |
306 | | void *private_data) |
307 | 0 | { |
308 | 0 | NTSTATUS status; |
309 | 0 | TALLOC_CTX *frame = talloc_stackframe(); |
310 | 0 | struct regval_ctr *values; |
311 | 0 | int i; |
312 | | |
313 | | /* loop over all of the predefined paths and add each component */ |
314 | |
|
315 | 0 | for (i=0; builtin_registry_paths[i] != NULL; i++) { |
316 | 0 | if (regdb_key_exists(db, builtin_registry_paths[i])) { |
317 | 0 | continue; |
318 | 0 | } |
319 | 0 | status = werror_to_ntstatus(init_registry_key_internal(db, |
320 | 0 | builtin_registry_paths[i])); |
321 | 0 | if (!NT_STATUS_IS_OK(status)) { |
322 | 0 | goto done; |
323 | 0 | } |
324 | 0 | } |
325 | | |
326 | | /* loop over all of the predefined values and add each component */ |
327 | | |
328 | 0 | for (i=0; builtin_registry_values[i].path != NULL; i++) { |
329 | 0 | WERROR werr; |
330 | |
|
331 | 0 | werr = regval_ctr_init(frame, &values); |
332 | 0 | if (!W_ERROR_IS_OK(werr)) { |
333 | 0 | status = werror_to_ntstatus(werr); |
334 | 0 | goto done; |
335 | 0 | } |
336 | | |
337 | 0 | regdb_fetch_values_internal(db, |
338 | 0 | builtin_registry_values[i].path, |
339 | 0 | values); |
340 | | |
341 | | /* preserve existing values across restarts. Only add new ones */ |
342 | |
|
343 | 0 | if (!regval_ctr_value_exists(values, |
344 | 0 | builtin_registry_values[i].valuename)) |
345 | 0 | { |
346 | 0 | regdb_ctr_add_value(values, |
347 | 0 | &builtin_registry_values[i]); |
348 | 0 | status = regdb_store_values_internal(db, |
349 | 0 | builtin_registry_values[i].path, |
350 | 0 | values); |
351 | 0 | if (!NT_STATUS_IS_OK(status)) { |
352 | 0 | goto done; |
353 | 0 | } |
354 | 0 | } |
355 | 0 | TALLOC_FREE(values); |
356 | 0 | } |
357 | | |
358 | 0 | status = NT_STATUS_OK; |
359 | |
|
360 | 0 | done: |
361 | |
|
362 | 0 | TALLOC_FREE(frame); |
363 | 0 | return status; |
364 | 0 | } |
365 | | |
366 | | WERROR init_registry_data(void) |
367 | 0 | { |
368 | 0 | WERROR werr; |
369 | 0 | TALLOC_CTX *frame = talloc_stackframe(); |
370 | 0 | struct regval_ctr *values; |
371 | 0 | int i; |
372 | | |
373 | | /* |
374 | | * First, check for the existence of the needed keys and values. |
375 | | * If all do already exist, we can save the writes. |
376 | | */ |
377 | 0 | for (i=0; builtin_registry_paths[i] != NULL; i++) { |
378 | 0 | if (!regdb_key_exists(regdb, builtin_registry_paths[i])) { |
379 | 0 | goto do_init; |
380 | 0 | } |
381 | 0 | } |
382 | | |
383 | 0 | for (i=0; builtin_registry_values[i].path != NULL; i++) { |
384 | 0 | werr = regval_ctr_init(frame, &values); |
385 | 0 | W_ERROR_NOT_OK_GOTO_DONE(werr); |
386 | | |
387 | 0 | regdb_fetch_values_internal(regdb, |
388 | 0 | builtin_registry_values[i].path, |
389 | 0 | values); |
390 | 0 | if (!regval_ctr_value_exists(values, |
391 | 0 | builtin_registry_values[i].valuename)) |
392 | 0 | { |
393 | 0 | TALLOC_FREE(values); |
394 | 0 | goto do_init; |
395 | 0 | } |
396 | | |
397 | 0 | TALLOC_FREE(values); |
398 | 0 | } |
399 | | |
400 | 0 | werr = WERR_OK; |
401 | 0 | goto done; |
402 | | |
403 | 0 | do_init: |
404 | | |
405 | | /* |
406 | | * There are potentially quite a few store operations which are all |
407 | | * individually wrapped in tdb transactions. Wrapping them in a single |
408 | | * transaction gives just a single transaction_commit() to actually do |
409 | | * its fsync()s. See tdb/common/transaction.c for info about nested |
410 | | * transaction behaviour. |
411 | | */ |
412 | |
|
413 | 0 | werr = regdb_trans_do(regdb, |
414 | 0 | init_registry_data_action, |
415 | 0 | NULL); |
416 | |
|
417 | 0 | done: |
418 | 0 | TALLOC_FREE(frame); |
419 | 0 | return werr; |
420 | 0 | } |
421 | | |
422 | | static int regdb_normalize_keynames_fn(struct db_record *rec, |
423 | | void *private_data) |
424 | 0 | { |
425 | 0 | TALLOC_CTX *mem_ctx = talloc_tos(); |
426 | 0 | const char *keyname; |
427 | 0 | NTSTATUS status; |
428 | 0 | TDB_DATA key; |
429 | 0 | TDB_DATA value; |
430 | 0 | struct db_context *db = (struct db_context *)private_data; |
431 | |
|
432 | 0 | key = dbwrap_record_get_key(rec); |
433 | 0 | if (key.dptr == NULL || key.dsize == 0) { |
434 | 0 | return 0; |
435 | 0 | } |
436 | | |
437 | 0 | value = dbwrap_record_get_value(rec); |
438 | |
|
439 | 0 | if (db == NULL) { |
440 | 0 | DEBUG(0, ("regdb_normalize_keynames_fn: ERROR: " |
441 | 0 | "NULL db context handed in via private_data\n")); |
442 | 0 | return 1; |
443 | 0 | } |
444 | | |
445 | 0 | if (strncmp((const char *)key.dptr, REGDB_VERSION_KEYNAME, |
446 | 0 | strlen(REGDB_VERSION_KEYNAME)) == 0) |
447 | 0 | { |
448 | 0 | return 0; |
449 | 0 | } |
450 | | |
451 | 0 | keyname = strchr((const char *)key.dptr, '/'); |
452 | 0 | if (keyname) { |
453 | 0 | keyname = talloc_string_sub(mem_ctx, |
454 | 0 | (const char *)key.dptr, |
455 | 0 | "/", |
456 | 0 | "\\"); |
457 | |
|
458 | 0 | DEBUG(2, ("regdb_normalize_keynames_fn: Convert %s to %s\n", |
459 | 0 | (const char *)key.dptr, |
460 | 0 | keyname)); |
461 | | |
462 | | /* Delete the original record and store the normalized key */ |
463 | 0 | status = dbwrap_record_delete(rec); |
464 | 0 | if (!NT_STATUS_IS_OK(status)) { |
465 | 0 | DEBUG(0,("regdb_normalize_keynames_fn: " |
466 | 0 | "tdb_delete for [%s] failed!\n", |
467 | 0 | (const char *)key.dptr)); |
468 | 0 | return 1; |
469 | 0 | } |
470 | | |
471 | 0 | status = dbwrap_store_bystring(db, keyname, value, TDB_REPLACE); |
472 | 0 | if (!NT_STATUS_IS_OK(status)) { |
473 | 0 | DEBUG(0,("regdb_normalize_keynames_fn: " |
474 | 0 | "failed to store new record for [%s]!\n", |
475 | 0 | keyname)); |
476 | 0 | return 1; |
477 | 0 | } |
478 | 0 | } |
479 | | |
480 | 0 | return 0; |
481 | 0 | } |
482 | | |
483 | | static WERROR regdb_store_regdb_version(struct db_context *db, uint32_t version) |
484 | 0 | { |
485 | 0 | NTSTATUS status; |
486 | 0 | if (db == NULL) { |
487 | 0 | return WERR_CAN_NOT_COMPLETE; |
488 | 0 | } |
489 | | |
490 | 0 | status = dbwrap_trans_store_int32_bystring(db, REGDB_VERSION_KEYNAME, |
491 | 0 | version); |
492 | 0 | if (!NT_STATUS_IS_OK(status)) { |
493 | 0 | DEBUG(1, ("regdb_store_regdb_version: error storing %s = %d: %s\n", |
494 | 0 | REGDB_VERSION_KEYNAME, version, nt_errstr(status))); |
495 | 0 | return ntstatus_to_werror(status); |
496 | 0 | } else { |
497 | 0 | DEBUG(10, ("regdb_store_regdb_version: stored %s = %d\n", |
498 | 0 | REGDB_VERSION_KEYNAME, version)); |
499 | 0 | return WERR_OK; |
500 | 0 | } |
501 | 0 | } |
502 | | |
503 | | static WERROR regdb_upgrade_v1_to_v2(struct db_context *db) |
504 | 0 | { |
505 | 0 | TALLOC_CTX *mem_ctx; |
506 | 0 | NTSTATUS status; |
507 | 0 | WERROR werr; |
508 | |
|
509 | 0 | mem_ctx = talloc_stackframe(); |
510 | |
|
511 | 0 | status = dbwrap_traverse(db, regdb_normalize_keynames_fn, db, NULL); |
512 | 0 | if (!NT_STATUS_IS_OK(status)) { |
513 | 0 | werr = WERR_REGISTRY_IO_FAILED; |
514 | 0 | goto done; |
515 | 0 | } |
516 | | |
517 | 0 | werr = regdb_store_regdb_version(db, REGDB_VERSION_V2); |
518 | |
|
519 | 0 | done: |
520 | 0 | talloc_free(mem_ctx); |
521 | 0 | return werr; |
522 | 0 | } |
523 | | |
524 | | static bool tdb_data_read_uint32(TDB_DATA *buf, uint32_t *result) |
525 | 0 | { |
526 | 0 | const size_t len = sizeof(uint32_t); |
527 | 0 | if (buf->dsize >= len) { |
528 | 0 | *result = IVAL(buf->dptr, 0); |
529 | 0 | buf->dptr += len; |
530 | 0 | buf->dsize -= len; |
531 | 0 | return true; |
532 | 0 | } |
533 | 0 | return false; |
534 | 0 | } |
535 | | |
536 | | static bool tdb_data_read_cstr(TDB_DATA *buf, char **result) |
537 | 0 | { |
538 | 0 | const size_t len = strnlen((char*)buf->dptr, buf->dsize) + 1; |
539 | 0 | if (buf->dsize >= len) { |
540 | 0 | *result = (char*)buf->dptr; |
541 | 0 | buf->dptr += len; |
542 | 0 | buf->dsize -= len; |
543 | 0 | return true; |
544 | 0 | } |
545 | 0 | return false; |
546 | 0 | } |
547 | | |
548 | 0 | static bool tdb_data_is_cstr(TDB_DATA d) { |
549 | 0 | if (tdb_data_is_empty(d) || (d.dptr[d.dsize-1] != '\0')) { |
550 | 0 | return false; |
551 | 0 | } |
552 | 0 | return strlen((char *)d.dptr) == (d.dsize-1); |
553 | 0 | } |
554 | | |
555 | | static bool upgrade_v2_to_v3_check_subkeylist(struct db_context *db, |
556 | | const char *key, |
557 | | const char *subkey) |
558 | 0 | { |
559 | 0 | static uint32_t zero = 0; |
560 | 0 | static TDB_DATA empty_subkey_list = { |
561 | 0 | .dptr = (unsigned char*)&zero, |
562 | 0 | .dsize = sizeof(uint32_t), |
563 | 0 | }; |
564 | 0 | bool success = false; |
565 | 0 | char *path = talloc_asprintf(talloc_tos(), "%s\\%s", key, subkey); |
566 | 0 | if (!strupper_m(path)) { |
567 | 0 | goto done; |
568 | 0 | } |
569 | | |
570 | 0 | if (!dbwrap_exists(db, string_term_tdb_data(path))) { |
571 | 0 | NTSTATUS status; |
572 | |
|
573 | 0 | DEBUG(10, ("regdb_upgrade_v2_to_v3: writing subkey list [%s]\n", |
574 | 0 | path)); |
575 | |
|
576 | 0 | status = dbwrap_store_bystring(db, path, empty_subkey_list, |
577 | 0 | TDB_INSERT); |
578 | 0 | if (!NT_STATUS_IS_OK(status)) { |
579 | 0 | DEBUG(0, ("regdb_upgrade_v2_to_v3: writing subkey list " |
580 | 0 | "[%s] failed\n", path)); |
581 | 0 | goto done; |
582 | 0 | } |
583 | 0 | } |
584 | 0 | success = true; |
585 | 0 | done: |
586 | 0 | talloc_free(path); |
587 | 0 | return success; |
588 | 0 | } |
589 | | |
590 | | static bool upgrade_v2_to_v3_check_parent(struct db_context *db, |
591 | | const char *key) |
592 | 0 | { |
593 | 0 | const char *sep = strrchr_m(key, '\\'); |
594 | 0 | if (sep != NULL) { |
595 | 0 | char *pkey = talloc_strndup(talloc_tos(), key, sep-key); |
596 | 0 | if (!dbwrap_exists(db, string_term_tdb_data(pkey))) { |
597 | 0 | DEBUG(0, ("regdb_upgrade_v2_to_v3: missing subkey list " |
598 | 0 | "[%s]\nrun \"net registry check\"\n", pkey)); |
599 | 0 | } |
600 | 0 | talloc_free(pkey); |
601 | 0 | } |
602 | 0 | return true; |
603 | 0 | } |
604 | | |
605 | | |
606 | 0 | #define IS_EQUAL(d,s) (((d).dsize == strlen(s)+1) && \ |
607 | 0 | (strcmp((char*)(d).dptr, (s)) == 0)) |
608 | 0 | #define STARTS_WITH(d,s) (((d).dsize > strlen(s)) && \ |
609 | 0 | (strncmp((char*)(d).dptr, (s), strlen(s)) == 0)) |
610 | | #define SSTR(d) (int)(d).dsize , (char*)(d).dptr |
611 | | |
612 | | |
613 | | static int regdb_upgrade_v2_to_v3_fn(struct db_record *rec, void *private_data) |
614 | 0 | { |
615 | 0 | struct db_context *db = (struct db_context *)private_data; |
616 | 0 | TDB_DATA key = dbwrap_record_get_key(rec); |
617 | 0 | TDB_DATA val = dbwrap_record_get_value(rec); |
618 | |
|
619 | 0 | if (tdb_data_is_empty(key)) { |
620 | 0 | return 0; |
621 | 0 | } |
622 | | |
623 | 0 | if (db == NULL) { |
624 | 0 | DEBUG(0, ("regdb_upgrade_v2_to_v3_fn: ERROR: " |
625 | 0 | "NULL db context handed in via private_data\n")); |
626 | 0 | return 1; |
627 | 0 | } |
628 | | |
629 | 0 | if (IS_EQUAL(key, REGDB_VERSION_KEYNAME) || |
630 | 0 | STARTS_WITH(key, REG_VALUE_PREFIX) || |
631 | 0 | STARTS_WITH(key, REG_SECDESC_PREFIX)) |
632 | 0 | { |
633 | 0 | DEBUG(10, ("regdb_upgrade_v2_to_v3: skipping [%.*s]\n", |
634 | 0 | SSTR(key))); |
635 | 0 | return 0; |
636 | 0 | } |
637 | | |
638 | 0 | if (STARTS_WITH(key, REG_SORTED_SUBKEYS_PREFIX)) { |
639 | 0 | NTSTATUS status; |
640 | | /* Delete the deprecated sorted subkeys cache. */ |
641 | |
|
642 | 0 | DEBUG(10, ("regdb_upgrade_v2_to_v3: deleting [%.*s]\n", |
643 | 0 | SSTR(key))); |
644 | |
|
645 | 0 | status = dbwrap_record_delete(rec); |
646 | 0 | if (!NT_STATUS_IS_OK(status)) { |
647 | 0 | DEBUG(0, ("regdb_upgrade_v2_to_v3: deleting [%.*s] " |
648 | 0 | "failed!\n", SSTR(key))); |
649 | 0 | return 1; |
650 | 0 | } |
651 | | |
652 | 0 | return 0; |
653 | 0 | } |
654 | | |
655 | 0 | if ( tdb_data_is_cstr(key) && |
656 | 0 | hive_info((char*)key.dptr) != NULL ) |
657 | 0 | { |
658 | | /* |
659 | | * Found a regular subkey list record. |
660 | | * Walk the list and create the list record for those |
661 | | * subkeys that don't already have one. |
662 | | */ |
663 | 0 | TDB_DATA pos = val; |
664 | 0 | char *subkey, *path = (char*)key.dptr; |
665 | 0 | uint32_t num_items, found_items = 0; |
666 | | |
667 | |
|
668 | 0 | DEBUG(10, ("regdb_upgrade_v2_to_v3: scanning subkeylist of " |
669 | 0 | "[%s]\n", path)); |
670 | |
|
671 | 0 | if (!tdb_data_read_uint32(&pos, &num_items)) { |
672 | | /* invalid or empty - skip */ |
673 | 0 | return 0; |
674 | 0 | } |
675 | | |
676 | 0 | while (tdb_data_read_cstr(&pos, &subkey)) { |
677 | 0 | found_items++; |
678 | |
|
679 | 0 | if (!upgrade_v2_to_v3_check_subkeylist(db, path, subkey)) |
680 | 0 | { |
681 | 0 | return 1; |
682 | 0 | } |
683 | | |
684 | 0 | if (!upgrade_v2_to_v3_check_parent(db, path)) { |
685 | 0 | return 1; |
686 | 0 | } |
687 | 0 | } |
688 | 0 | if (found_items != num_items) { |
689 | 0 | DEBUG(0, ("regdb_upgrade_v2_to_v3: inconsistent subkey " |
690 | 0 | "list [%s]\nrun \"net registry check\"\n", |
691 | 0 | path)); |
692 | 0 | } |
693 | 0 | } else { |
694 | 0 | DEBUG(10, ("regdb_upgrade_v2_to_v3: skipping invalid [%.*s]\n" |
695 | 0 | "run \"net registry check\"\n", SSTR(key))); |
696 | 0 | } |
697 | | |
698 | 0 | return 0; |
699 | 0 | } |
700 | | |
701 | | static WERROR regdb_upgrade_v2_to_v3(struct db_context *db) |
702 | 0 | { |
703 | 0 | NTSTATUS status; |
704 | 0 | WERROR werr; |
705 | |
|
706 | 0 | status = dbwrap_traverse(db, regdb_upgrade_v2_to_v3_fn, db, NULL); |
707 | 0 | if (!NT_STATUS_IS_OK(status)) { |
708 | 0 | werr = WERR_REGISTRY_IO_FAILED; |
709 | 0 | goto done; |
710 | 0 | } |
711 | | |
712 | 0 | werr = regdb_store_regdb_version(db, REGDB_VERSION_V3); |
713 | |
|
714 | 0 | done: |
715 | 0 | return werr; |
716 | 0 | } |
717 | | |
718 | | /*********************************************************************** |
719 | | Open the registry database |
720 | | ***********************************************************************/ |
721 | | |
722 | | WERROR regdb_init(void) |
723 | 0 | { |
724 | 0 | int32_t vers_id; |
725 | 0 | WERROR werr; |
726 | 0 | NTSTATUS status; |
727 | 0 | char *db_path; |
728 | |
|
729 | 0 | if (regdb) { |
730 | 0 | DEBUG(10, ("regdb_init: incrementing refcount (%d->%d)\n", |
731 | 0 | regdb_refcount, regdb_refcount+1)); |
732 | 0 | regdb_refcount++; |
733 | 0 | return WERR_OK; |
734 | 0 | } |
735 | | |
736 | | /* |
737 | | * Clustered Samba can only work as root because we need messaging to |
738 | | * talk to ctdb which only works as root. |
739 | | */ |
740 | 0 | if (!uid_wrapper_enabled() && lp_clustering() && geteuid() != 0) { |
741 | 0 | DBG_ERR("Cluster mode requires running as root.\n"); |
742 | 0 | return WERR_ACCESS_DENIED; |
743 | 0 | } |
744 | | |
745 | 0 | db_path = state_path(talloc_tos(), "registry.tdb"); |
746 | 0 | if (db_path == NULL) { |
747 | 0 | return WERR_NOT_ENOUGH_MEMORY; |
748 | 0 | } |
749 | | |
750 | 0 | regdb = db_open(NULL, db_path, 0, |
751 | 0 | REG_TDB_FLAGS, O_RDWR, 0600, |
752 | 0 | DBWRAP_LOCK_ORDER_1, REG_DBWRAP_FLAGS); |
753 | 0 | if (!regdb) { |
754 | 0 | regdb = db_open(NULL, db_path, 0, |
755 | 0 | REG_TDB_FLAGS, O_RDWR|O_CREAT, 0600, |
756 | 0 | DBWRAP_LOCK_ORDER_1, REG_DBWRAP_FLAGS); |
757 | 0 | if (!regdb) { |
758 | 0 | werr = ntstatus_to_werror(map_nt_error_from_unix(errno)); |
759 | 0 | DEBUG(1,("regdb_init: Failed to open registry %s (%s)\n", |
760 | 0 | db_path, strerror(errno) )); |
761 | 0 | TALLOC_FREE(db_path); |
762 | 0 | return werr; |
763 | 0 | } |
764 | | |
765 | 0 | werr = regdb_store_regdb_version(regdb, REGDB_CODE_VERSION); |
766 | 0 | if (!W_ERROR_IS_OK(werr)) { |
767 | 0 | DEBUG(1, ("regdb_init: Failed to store version: %s\n", |
768 | 0 | win_errstr(werr))); |
769 | 0 | TALLOC_FREE(db_path); |
770 | 0 | return werr; |
771 | 0 | } |
772 | | |
773 | 0 | DEBUG(10,("regdb_init: Successfully created registry tdb\n")); |
774 | 0 | } |
775 | 0 | TALLOC_FREE(db_path); |
776 | |
|
777 | 0 | regdb_refcount = 1; |
778 | 0 | DEBUG(10, ("regdb_init: registry db opened. refcount reset (%d)\n", |
779 | 0 | regdb_refcount)); |
780 | |
|
781 | 0 | status = dbwrap_fetch_int32_bystring(regdb, REGDB_VERSION_KEYNAME, |
782 | 0 | &vers_id); |
783 | 0 | if (!NT_STATUS_IS_OK(status)) { |
784 | 0 | DBG_DEBUG("Reading registry version failed: %s, " |
785 | 0 | "initializing to version %d\n", |
786 | 0 | nt_errstr(status), REGDB_VERSION_V1); |
787 | | |
788 | | /* |
789 | | * There was a regdb format version prior to version 1 |
790 | | * which did not store a INFO/version key. The format |
791 | | * of this version was identical to version 1 except for |
792 | | * the lack of the sorted subkey cache records. |
793 | | * Since these are disposable, we can safely assume version |
794 | | * 1 if no INFO/version key is found and run the db through |
795 | | * the whole chain of upgrade. If the database was not |
796 | | * initialized, this does not harm. If it was the unversioned |
797 | | * version ("0"), then it do the right thing with the records. |
798 | | */ |
799 | 0 | werr = regdb_store_regdb_version(regdb, REGDB_VERSION_V1); |
800 | 0 | if (!W_ERROR_IS_OK(werr)) { |
801 | 0 | return werr; |
802 | 0 | } |
803 | 0 | vers_id = REGDB_VERSION_V1; |
804 | 0 | } |
805 | | |
806 | 0 | if (vers_id == REGDB_CODE_VERSION) { |
807 | 0 | return WERR_OK; |
808 | 0 | } |
809 | | |
810 | 0 | if (vers_id > REGDB_CODE_VERSION || vers_id == 0) { |
811 | 0 | DEBUG(0, ("regdb_init: unknown registry version %d " |
812 | 0 | "(code version = %d), refusing initialization\n", |
813 | 0 | vers_id, REGDB_CODE_VERSION)); |
814 | 0 | return WERR_CAN_NOT_COMPLETE; |
815 | 0 | } |
816 | | |
817 | 0 | if (dbwrap_transaction_start(regdb) != 0) { |
818 | 0 | return WERR_REGISTRY_IO_FAILED; |
819 | 0 | } |
820 | | |
821 | 0 | if (vers_id == REGDB_VERSION_V1) { |
822 | 0 | DEBUG(10, ("regdb_init: upgrading registry from version %d " |
823 | 0 | "to %d\n", REGDB_VERSION_V1, REGDB_VERSION_V2)); |
824 | |
|
825 | 0 | werr = regdb_upgrade_v1_to_v2(regdb); |
826 | 0 | if (!W_ERROR_IS_OK(werr)) { |
827 | 0 | dbwrap_transaction_cancel(regdb); |
828 | 0 | return werr; |
829 | 0 | } |
830 | | |
831 | 0 | vers_id = REGDB_VERSION_V2; |
832 | 0 | } |
833 | | |
834 | 0 | if (vers_id == REGDB_VERSION_V2) { |
835 | 0 | DEBUG(10, ("regdb_init: upgrading registry from version %d " |
836 | 0 | "to %d\n", REGDB_VERSION_V2, REGDB_VERSION_V3)); |
837 | |
|
838 | 0 | werr = regdb_upgrade_v2_to_v3(regdb); |
839 | 0 | if (!W_ERROR_IS_OK(werr)) { |
840 | 0 | dbwrap_transaction_cancel(regdb); |
841 | 0 | return werr; |
842 | 0 | } |
843 | | |
844 | 0 | vers_id = REGDB_VERSION_V3; |
845 | 0 | } |
846 | | |
847 | | /* future upgrade code should go here */ |
848 | | |
849 | 0 | if (dbwrap_transaction_commit(regdb) != 0) { |
850 | 0 | return WERR_REGISTRY_IO_FAILED; |
851 | 0 | } |
852 | | |
853 | 0 | return WERR_OK; |
854 | 0 | } |
855 | | |
856 | | /*********************************************************************** |
857 | | Open the registry. Must already have been initialized by regdb_init() |
858 | | ***********************************************************************/ |
859 | | |
860 | | WERROR regdb_open( void ) |
861 | 0 | { |
862 | 0 | WERROR result; |
863 | 0 | char *db_path = NULL; |
864 | 0 | int saved_errno; |
865 | |
|
866 | 0 | if ( regdb ) { |
867 | 0 | DEBUG(10, ("regdb_open: incrementing refcount (%d->%d)\n", |
868 | 0 | regdb_refcount, regdb_refcount+1)); |
869 | 0 | regdb_refcount++; |
870 | 0 | result = WERR_OK; |
871 | 0 | goto done; |
872 | 0 | } |
873 | | |
874 | 0 | db_path = state_path(talloc_tos(), "registry.tdb"); |
875 | 0 | if (db_path == NULL) { |
876 | 0 | result = WERR_NOT_ENOUGH_MEMORY; |
877 | 0 | goto done; |
878 | 0 | } |
879 | | |
880 | 0 | become_root(); |
881 | |
|
882 | 0 | regdb = db_open(NULL, db_path, 0, |
883 | 0 | REG_TDB_FLAGS, O_RDWR, 0600, |
884 | 0 | DBWRAP_LOCK_ORDER_1, REG_DBWRAP_FLAGS); |
885 | 0 | saved_errno = errno; |
886 | 0 | unbecome_root(); |
887 | 0 | if ( !regdb ) { |
888 | 0 | result = ntstatus_to_werror(map_nt_error_from_unix(saved_errno)); |
889 | 0 | DEBUG(0,("regdb_open: Failed to open %s! (%s)\n", |
890 | 0 | db_path, strerror(saved_errno))); |
891 | 0 | goto done; |
892 | 0 | } |
893 | | |
894 | 0 | regdb_refcount = 1; |
895 | 0 | DEBUG(10, ("regdb_open: registry db opened. refcount reset (%d)\n", |
896 | 0 | regdb_refcount)); |
897 | |
|
898 | 0 | result = WERR_OK; |
899 | 0 | done: |
900 | 0 | TALLOC_FREE(db_path); |
901 | 0 | return result; |
902 | 0 | } |
903 | | |
904 | | /*********************************************************************** |
905 | | ***********************************************************************/ |
906 | | |
907 | | int regdb_close( void ) |
908 | 0 | { |
909 | 0 | if (regdb_refcount == 0) { |
910 | 0 | return 0; |
911 | 0 | } |
912 | | |
913 | 0 | regdb_refcount--; |
914 | |
|
915 | 0 | DEBUG(10, ("regdb_close: decrementing refcount (%d->%d)\n", |
916 | 0 | regdb_refcount+1, regdb_refcount)); |
917 | |
|
918 | 0 | if ( regdb_refcount > 0 ) |
919 | 0 | return 0; |
920 | | |
921 | 0 | SMB_ASSERT( regdb_refcount >= 0 ); |
922 | | |
923 | 0 | TALLOC_FREE(regdb); |
924 | 0 | return 0; |
925 | 0 | } |
926 | | |
927 | | WERROR regdb_transaction_start(void) |
928 | 0 | { |
929 | 0 | return (dbwrap_transaction_start(regdb) == 0) ? |
930 | 0 | WERR_OK : WERR_REGISTRY_IO_FAILED; |
931 | 0 | } |
932 | | |
933 | | WERROR regdb_transaction_commit(void) |
934 | 0 | { |
935 | 0 | return (dbwrap_transaction_commit(regdb) == 0) ? |
936 | 0 | WERR_OK : WERR_REGISTRY_IO_FAILED; |
937 | 0 | } |
938 | | |
939 | | WERROR regdb_transaction_cancel(void) |
940 | 0 | { |
941 | 0 | return (dbwrap_transaction_cancel(regdb) == 0) ? |
942 | 0 | WERR_OK : WERR_REGISTRY_IO_FAILED; |
943 | 0 | } |
944 | | |
945 | | /*********************************************************************** |
946 | | return the tdb sequence number of the registry tdb. |
947 | | this is an indicator for the content of the registry |
948 | | having changed. it will change upon regdb_init, too, though. |
949 | | ***********************************************************************/ |
950 | | int regdb_get_seqnum(void) |
951 | 0 | { |
952 | 0 | return dbwrap_get_seqnum(regdb); |
953 | 0 | } |
954 | | |
955 | | |
956 | | static WERROR regdb_delete_key_with_prefix(struct db_context *db, |
957 | | const char *keyname, |
958 | | const char *prefix) |
959 | 0 | { |
960 | 0 | char *path; |
961 | 0 | WERROR werr = WERR_NOT_ENOUGH_MEMORY; |
962 | 0 | TALLOC_CTX *mem_ctx = talloc_stackframe(); |
963 | |
|
964 | 0 | if (keyname == NULL) { |
965 | 0 | werr = WERR_INVALID_PARAMETER; |
966 | 0 | goto done; |
967 | 0 | } |
968 | | |
969 | 0 | if (prefix == NULL) { |
970 | 0 | path = discard_const_p(char, keyname); |
971 | 0 | } else { |
972 | 0 | path = talloc_asprintf(mem_ctx, "%s\\%s", prefix, keyname); |
973 | 0 | if (path == NULL) { |
974 | 0 | goto done; |
975 | 0 | } |
976 | 0 | } |
977 | | |
978 | 0 | path = normalize_reg_path(mem_ctx, path); |
979 | 0 | if (path == NULL) { |
980 | 0 | goto done; |
981 | 0 | } |
982 | | |
983 | 0 | werr = ntstatus_to_werror(dbwrap_purge_bystring(db, path)); |
984 | |
|
985 | 0 | done: |
986 | 0 | talloc_free(mem_ctx); |
987 | 0 | return werr; |
988 | 0 | } |
989 | | |
990 | | |
991 | | static WERROR regdb_delete_values(struct db_context *db, const char *keyname) |
992 | 0 | { |
993 | 0 | return regdb_delete_key_with_prefix(db, keyname, REG_VALUE_PREFIX); |
994 | 0 | } |
995 | | |
996 | | static WERROR regdb_delete_secdesc(struct db_context *db, const char *keyname) |
997 | 0 | { |
998 | 0 | return regdb_delete_key_with_prefix(db, keyname, REG_SECDESC_PREFIX); |
999 | 0 | } |
1000 | | |
1001 | | static WERROR regdb_delete_subkeylist(struct db_context *db, const char *keyname) |
1002 | 0 | { |
1003 | 0 | return regdb_delete_key_with_prefix(db, keyname, NULL); |
1004 | 0 | } |
1005 | | |
1006 | | |
1007 | | static WERROR regdb_delete_key_lists(struct db_context *db, const char *keyname) |
1008 | 0 | { |
1009 | 0 | WERROR werr; |
1010 | |
|
1011 | 0 | werr = regdb_delete_values(db, keyname); |
1012 | 0 | if (!W_ERROR_IS_OK(werr)) { |
1013 | 0 | DEBUG(1, (__location__ " Deleting %s\\%s failed: %s\n", |
1014 | 0 | REG_VALUE_PREFIX, keyname, win_errstr(werr))); |
1015 | 0 | goto done; |
1016 | 0 | } |
1017 | | |
1018 | 0 | werr = regdb_delete_secdesc(db, keyname); |
1019 | 0 | if (!W_ERROR_IS_OK(werr)) { |
1020 | 0 | DEBUG(1, (__location__ " Deleting %s\\%s failed: %s\n", |
1021 | 0 | REG_SECDESC_PREFIX, keyname, win_errstr(werr))); |
1022 | 0 | goto done; |
1023 | 0 | } |
1024 | | |
1025 | 0 | werr = regdb_delete_subkeylist(db, keyname); |
1026 | 0 | if (!W_ERROR_IS_OK(werr)) { |
1027 | 0 | DEBUG(1, (__location__ " Deleting %s failed: %s\n", |
1028 | 0 | keyname, win_errstr(werr))); |
1029 | 0 | goto done; |
1030 | 0 | } |
1031 | | |
1032 | 0 | done: |
1033 | 0 | return werr; |
1034 | 0 | } |
1035 | | |
1036 | | /*********************************************************************** |
1037 | | Add subkey strings to the registry tdb under a defined key |
1038 | | fmt is the same format as tdb_pack except this function only supports |
1039 | | fstrings |
1040 | | ***********************************************************************/ |
1041 | | |
1042 | | static WERROR regdb_store_keys_internal2(struct db_context *db, |
1043 | | const char *key, |
1044 | | struct regsubkey_ctr *ctr) |
1045 | 0 | { |
1046 | 0 | TDB_DATA dbuf; |
1047 | 0 | uint8_t *buffer = NULL; |
1048 | 0 | uint32_t i = 0; |
1049 | 0 | uint32_t len, buflen; |
1050 | 0 | uint32_t num_subkeys = regsubkey_ctr_numkeys(ctr); |
1051 | 0 | char *keyname = NULL; |
1052 | 0 | TALLOC_CTX *ctx = talloc_stackframe(); |
1053 | 0 | WERROR werr; |
1054 | |
|
1055 | 0 | if (!key) { |
1056 | 0 | werr = WERR_INVALID_PARAMETER; |
1057 | 0 | goto done; |
1058 | 0 | } |
1059 | | |
1060 | 0 | keyname = talloc_strdup(ctx, key); |
1061 | 0 | if (!keyname) { |
1062 | 0 | werr = WERR_NOT_ENOUGH_MEMORY; |
1063 | 0 | goto done; |
1064 | 0 | } |
1065 | | |
1066 | 0 | keyname = normalize_reg_path(ctx, keyname); |
1067 | 0 | if (!keyname) { |
1068 | 0 | werr = WERR_NOT_ENOUGH_MEMORY; |
1069 | 0 | goto done; |
1070 | 0 | } |
1071 | | |
1072 | | /* allocate some initial memory */ |
1073 | | |
1074 | 0 | buffer = (uint8_t *)SMB_MALLOC(1024); |
1075 | 0 | if (buffer == NULL) { |
1076 | 0 | werr = WERR_NOT_ENOUGH_MEMORY; |
1077 | 0 | goto done; |
1078 | 0 | } |
1079 | 0 | buflen = 1024; |
1080 | 0 | len = 0; |
1081 | | |
1082 | | /* store the number of subkeys */ |
1083 | |
|
1084 | 0 | len += tdb_pack(buffer+len, buflen-len, "d", num_subkeys); |
1085 | | |
1086 | | /* pack all the strings */ |
1087 | |
|
1088 | 0 | for (i=0; i<num_subkeys; i++) { |
1089 | 0 | size_t thistime; |
1090 | |
|
1091 | 0 | thistime = tdb_pack(buffer+len, buflen-len, "f", |
1092 | 0 | regsubkey_ctr_specific_key(ctr, i)); |
1093 | 0 | if (len+thistime > buflen) { |
1094 | 0 | size_t thistime2; |
1095 | | /* |
1096 | | * tdb_pack hasn't done anything because of the short |
1097 | | * buffer, allocate extra space. |
1098 | | */ |
1099 | 0 | buffer = SMB_REALLOC_ARRAY(buffer, uint8_t, |
1100 | 0 | (len+thistime)*2); |
1101 | 0 | if(buffer == NULL) { |
1102 | 0 | DEBUG(0, ("regdb_store_keys: Failed to realloc " |
1103 | 0 | "memory of size [%u]\n", |
1104 | 0 | (unsigned int)(len+thistime)*2)); |
1105 | 0 | werr = WERR_NOT_ENOUGH_MEMORY; |
1106 | 0 | goto done; |
1107 | 0 | } |
1108 | 0 | buflen = (len+thistime)*2; |
1109 | 0 | thistime2 = tdb_pack( |
1110 | 0 | buffer+len, buflen-len, "f", |
1111 | 0 | regsubkey_ctr_specific_key(ctr, i)); |
1112 | 0 | if (thistime2 != thistime) { |
1113 | 0 | DEBUG(0, ("tdb_pack failed\n")); |
1114 | 0 | werr = WERR_CAN_NOT_COMPLETE; |
1115 | 0 | goto done; |
1116 | 0 | } |
1117 | 0 | } |
1118 | 0 | len += thistime; |
1119 | 0 | } |
1120 | | |
1121 | | /* finally write out the data */ |
1122 | | |
1123 | 0 | dbuf.dptr = buffer; |
1124 | 0 | dbuf.dsize = len; |
1125 | 0 | werr = ntstatus_to_werror(dbwrap_store_bystring(db, keyname, dbuf, |
1126 | 0 | TDB_REPLACE)); |
1127 | |
|
1128 | 0 | done: |
1129 | 0 | TALLOC_FREE(ctx); |
1130 | 0 | SAFE_FREE(buffer); |
1131 | 0 | return werr; |
1132 | 0 | } |
1133 | | |
1134 | | /** |
1135 | | * Utility function to store a new empty list of |
1136 | | * subkeys of given key specified as parent and subkey name |
1137 | | * (thereby creating the key). |
1138 | | * If the parent keyname is NULL, then the "subkey" is |
1139 | | * interpreted as a base key. |
1140 | | * If the subkey list does already exist, it is not modified. |
1141 | | * |
1142 | | * Must be called from within a transaction. |
1143 | | */ |
1144 | | static WERROR regdb_store_subkey_list(struct db_context *db, const char *parent, |
1145 | | const char *key) |
1146 | 0 | { |
1147 | 0 | WERROR werr; |
1148 | 0 | char *path = NULL; |
1149 | 0 | struct regsubkey_ctr *subkeys = NULL; |
1150 | 0 | TALLOC_CTX *frame = talloc_stackframe(); |
1151 | |
|
1152 | 0 | if (parent == NULL) { |
1153 | 0 | path = talloc_strdup(frame, key); |
1154 | 0 | } else { |
1155 | 0 | path = talloc_asprintf(frame, "%s\\%s", parent, key); |
1156 | 0 | } |
1157 | 0 | if (!path) { |
1158 | 0 | werr = WERR_NOT_ENOUGH_MEMORY; |
1159 | 0 | goto done; |
1160 | 0 | } |
1161 | | |
1162 | 0 | werr = regsubkey_ctr_init(frame, &subkeys); |
1163 | 0 | W_ERROR_NOT_OK_GOTO_DONE(werr); |
1164 | | |
1165 | 0 | werr = regdb_fetch_keys_internal(db, path, subkeys); |
1166 | 0 | if (W_ERROR_IS_OK(werr)) { |
1167 | | /* subkey list exists already - don't modify */ |
1168 | 0 | goto done; |
1169 | 0 | } |
1170 | | |
1171 | 0 | werr = regsubkey_ctr_reinit(subkeys); |
1172 | 0 | W_ERROR_NOT_OK_GOTO_DONE(werr); |
1173 | | |
1174 | | /* create a record with 0 subkeys */ |
1175 | 0 | werr = regdb_store_keys_internal2(db, path, subkeys); |
1176 | 0 | if (!W_ERROR_IS_OK(werr)) { |
1177 | 0 | DEBUG(0, ("regdb_store_keys: Failed to store new record for " |
1178 | 0 | "key [%s]: %s\n", path, win_errstr(werr))); |
1179 | 0 | goto done; |
1180 | 0 | } |
1181 | | |
1182 | 0 | done: |
1183 | 0 | talloc_free(frame); |
1184 | 0 | return werr; |
1185 | 0 | } |
1186 | | |
1187 | | /*********************************************************************** |
1188 | | Store the new subkey record and create any child key records that |
1189 | | do not currently exist |
1190 | | ***********************************************************************/ |
1191 | | |
1192 | | struct regdb_store_keys_context { |
1193 | | const char *key; |
1194 | | struct regsubkey_ctr *ctr; |
1195 | | }; |
1196 | | |
1197 | | static NTSTATUS regdb_store_keys_action(struct db_context *db, |
1198 | | void *private_data) |
1199 | 0 | { |
1200 | 0 | struct regdb_store_keys_context *store_ctx; |
1201 | 0 | WERROR werr; |
1202 | 0 | int num_subkeys, i; |
1203 | 0 | char *path = NULL; |
1204 | 0 | struct regsubkey_ctr *old_subkeys = NULL; |
1205 | 0 | char *oldkeyname = NULL; |
1206 | 0 | TALLOC_CTX *mem_ctx = talloc_stackframe(); |
1207 | |
|
1208 | 0 | store_ctx = (struct regdb_store_keys_context *)private_data; |
1209 | | |
1210 | | /* |
1211 | | * Re-fetch the old keys inside the transaction |
1212 | | */ |
1213 | |
|
1214 | 0 | werr = regsubkey_ctr_init(mem_ctx, &old_subkeys); |
1215 | 0 | W_ERROR_NOT_OK_GOTO_DONE(werr); |
1216 | | |
1217 | 0 | werr = regdb_fetch_keys_internal(db, store_ctx->key, old_subkeys); |
1218 | 0 | if (!W_ERROR_IS_OK(werr) && |
1219 | 0 | !W_ERROR_EQUAL(werr, WERR_NOT_FOUND)) |
1220 | 0 | { |
1221 | 0 | goto done; |
1222 | 0 | } |
1223 | | |
1224 | | /* |
1225 | | * Make the store operation as safe as possible without transactions: |
1226 | | * |
1227 | | * (1) For each subkey removed from ctr compared with old_subkeys: |
1228 | | * |
1229 | | * (a) First delete the value db entry. |
1230 | | * |
1231 | | * (b) Next delete the secdesc db record. |
1232 | | * |
1233 | | * (c) Then delete the subkey list entry. |
1234 | | * |
1235 | | * (2) Now write the list of subkeys of the parent key, |
1236 | | * deleting removed entries and adding new ones. |
1237 | | * |
1238 | | * (3) Finally create the subkey list entries for the added keys. |
1239 | | * |
1240 | | * This way if we crash half-way in between deleting the subkeys |
1241 | | * and storing the parent's list of subkeys, no old data can pop up |
1242 | | * out of the blue when re-adding keys later on. |
1243 | | */ |
1244 | | |
1245 | | /* (1) delete removed keys' lists (values/secdesc/subkeys) */ |
1246 | | |
1247 | 0 | num_subkeys = regsubkey_ctr_numkeys(old_subkeys); |
1248 | 0 | for (i=0; i<num_subkeys; i++) { |
1249 | 0 | oldkeyname = regsubkey_ctr_specific_key(old_subkeys, i); |
1250 | |
|
1251 | 0 | if (regsubkey_ctr_key_exists(store_ctx->ctr, oldkeyname)) { |
1252 | | /* |
1253 | | * It's still around, don't delete |
1254 | | */ |
1255 | 0 | continue; |
1256 | 0 | } |
1257 | | |
1258 | 0 | path = talloc_asprintf(mem_ctx, "%s\\%s", store_ctx->key, |
1259 | 0 | oldkeyname); |
1260 | 0 | if (!path) { |
1261 | 0 | werr = WERR_NOT_ENOUGH_MEMORY; |
1262 | 0 | goto done; |
1263 | 0 | } |
1264 | | |
1265 | 0 | werr = regdb_delete_key_lists(db, path); |
1266 | 0 | W_ERROR_NOT_OK_GOTO_DONE(werr); |
1267 | | |
1268 | 0 | TALLOC_FREE(path); |
1269 | 0 | } |
1270 | | |
1271 | 0 | TALLOC_FREE(old_subkeys); |
1272 | | |
1273 | | /* (2) store the subkey list for the parent */ |
1274 | |
|
1275 | 0 | werr = regdb_store_keys_internal2(db, store_ctx->key, store_ctx->ctr); |
1276 | 0 | if (!W_ERROR_IS_OK(werr)) { |
1277 | 0 | DEBUG(0,("regdb_store_keys: Failed to store new subkey list " |
1278 | 0 | "for parent [%s]: %s\n", store_ctx->key, |
1279 | 0 | win_errstr(werr))); |
1280 | 0 | goto done; |
1281 | 0 | } |
1282 | | |
1283 | | /* (3) now create records for any subkeys that don't already exist */ |
1284 | | |
1285 | 0 | num_subkeys = regsubkey_ctr_numkeys(store_ctx->ctr); |
1286 | |
|
1287 | 0 | for (i=0; i<num_subkeys; i++) { |
1288 | 0 | const char *subkey; |
1289 | |
|
1290 | 0 | subkey = regsubkey_ctr_specific_key(store_ctx->ctr, i); |
1291 | |
|
1292 | 0 | werr = regdb_store_subkey_list(db, store_ctx->key, subkey); |
1293 | 0 | W_ERROR_NOT_OK_GOTO_DONE(werr); |
1294 | 0 | } |
1295 | | |
1296 | | /* |
1297 | | * Update the seqnum in the container to possibly |
1298 | | * prevent next read from going to disk |
1299 | | */ |
1300 | 0 | werr = regsubkey_ctr_set_seqnum(store_ctx->ctr, dbwrap_get_seqnum(db)); |
1301 | |
|
1302 | 0 | done: |
1303 | 0 | talloc_free(mem_ctx); |
1304 | 0 | return werror_to_ntstatus(werr); |
1305 | 0 | } |
1306 | | |
1307 | | static bool regdb_store_keys_internal(struct db_context *db, const char *key, |
1308 | | struct regsubkey_ctr *ctr) |
1309 | 0 | { |
1310 | 0 | int num_subkeys, old_num_subkeys, i; |
1311 | 0 | struct regsubkey_ctr *old_subkeys = NULL; |
1312 | 0 | TALLOC_CTX *ctx = talloc_stackframe(); |
1313 | 0 | WERROR werr; |
1314 | 0 | bool ret = false; |
1315 | 0 | struct regdb_store_keys_context store_ctx; |
1316 | |
|
1317 | 0 | if (!regdb_key_exists(db, key)) { |
1318 | 0 | goto done; |
1319 | 0 | } |
1320 | | |
1321 | | /* |
1322 | | * fetch a list of the old subkeys so we can determine if anything has |
1323 | | * changed |
1324 | | */ |
1325 | | |
1326 | 0 | werr = regsubkey_ctr_init(ctx, &old_subkeys); |
1327 | 0 | if (!W_ERROR_IS_OK(werr)) { |
1328 | 0 | DEBUG(0,("regdb_store_keys: talloc() failure!\n")); |
1329 | 0 | goto done; |
1330 | 0 | } |
1331 | | |
1332 | 0 | werr = regdb_fetch_keys_internal(db, key, old_subkeys); |
1333 | 0 | if (!W_ERROR_IS_OK(werr) && |
1334 | 0 | !W_ERROR_EQUAL(werr, WERR_NOT_FOUND)) |
1335 | 0 | { |
1336 | 0 | goto done; |
1337 | 0 | } |
1338 | | |
1339 | 0 | num_subkeys = regsubkey_ctr_numkeys(ctr); |
1340 | 0 | old_num_subkeys = regsubkey_ctr_numkeys(old_subkeys); |
1341 | 0 | if ((num_subkeys && old_num_subkeys) && |
1342 | 0 | (num_subkeys == old_num_subkeys)) { |
1343 | |
|
1344 | 0 | for (i = 0; i < num_subkeys; i++) { |
1345 | 0 | if (strcmp(regsubkey_ctr_specific_key(ctr, i), |
1346 | 0 | regsubkey_ctr_specific_key(old_subkeys, i)) |
1347 | 0 | != 0) |
1348 | 0 | { |
1349 | 0 | break; |
1350 | 0 | } |
1351 | 0 | } |
1352 | 0 | if (i == num_subkeys) { |
1353 | | /* |
1354 | | * Nothing changed, no point to even start a tdb |
1355 | | * transaction |
1356 | | */ |
1357 | |
|
1358 | 0 | ret = true; |
1359 | 0 | goto done; |
1360 | 0 | } |
1361 | 0 | } |
1362 | | |
1363 | 0 | TALLOC_FREE(old_subkeys); |
1364 | |
|
1365 | 0 | store_ctx.key = key; |
1366 | 0 | store_ctx.ctr = ctr; |
1367 | |
|
1368 | 0 | werr = regdb_trans_do(db, |
1369 | 0 | regdb_store_keys_action, |
1370 | 0 | &store_ctx); |
1371 | |
|
1372 | 0 | ret = W_ERROR_IS_OK(werr); |
1373 | |
|
1374 | 0 | done: |
1375 | 0 | TALLOC_FREE(ctx); |
1376 | |
|
1377 | 0 | return ret; |
1378 | 0 | } |
1379 | | |
1380 | | static bool regdb_store_keys(const char *key, struct regsubkey_ctr *ctr) |
1381 | 0 | { |
1382 | 0 | return regdb_store_keys_internal(regdb, key, ctr); |
1383 | 0 | } |
1384 | | |
1385 | | /** |
1386 | | * create a subkey of a given key |
1387 | | */ |
1388 | | |
1389 | | struct regdb_create_subkey_context { |
1390 | | const char *key; |
1391 | | const char *subkey; |
1392 | | }; |
1393 | | |
1394 | | static NTSTATUS regdb_create_subkey_action(struct db_context *db, |
1395 | | void *private_data) |
1396 | 0 | { |
1397 | 0 | WERROR werr; |
1398 | 0 | struct regdb_create_subkey_context *create_ctx; |
1399 | 0 | struct regsubkey_ctr *subkeys; |
1400 | 0 | TALLOC_CTX *mem_ctx = talloc_stackframe(); |
1401 | |
|
1402 | 0 | create_ctx = (struct regdb_create_subkey_context *)private_data; |
1403 | |
|
1404 | 0 | werr = regsubkey_ctr_init(mem_ctx, &subkeys); |
1405 | 0 | W_ERROR_NOT_OK_GOTO_DONE(werr); |
1406 | | |
1407 | 0 | werr = regdb_fetch_keys_internal(db, create_ctx->key, subkeys); |
1408 | 0 | W_ERROR_NOT_OK_GOTO_DONE(werr); |
1409 | | |
1410 | 0 | werr = regsubkey_ctr_addkey(subkeys, create_ctx->subkey); |
1411 | 0 | W_ERROR_NOT_OK_GOTO_DONE(werr); |
1412 | | |
1413 | 0 | werr = regdb_store_keys_internal2(db, create_ctx->key, subkeys); |
1414 | 0 | if (!W_ERROR_IS_OK(werr)) { |
1415 | 0 | DEBUG(0, (__location__ " failed to store new subkey list for " |
1416 | 0 | "parent key %s: %s\n", create_ctx->key, |
1417 | 0 | win_errstr(werr))); |
1418 | 0 | } |
1419 | |
|
1420 | 0 | werr = regdb_store_subkey_list(db, create_ctx->key, create_ctx->subkey); |
1421 | |
|
1422 | 0 | done: |
1423 | 0 | talloc_free(mem_ctx); |
1424 | 0 | return werror_to_ntstatus(werr); |
1425 | 0 | } |
1426 | | |
1427 | | static WERROR regdb_create_subkey_internal(struct db_context *db, |
1428 | | const char *key, |
1429 | | const char *subkey) |
1430 | 0 | { |
1431 | 0 | WERROR werr; |
1432 | 0 | struct regsubkey_ctr *subkeys; |
1433 | 0 | TALLOC_CTX *mem_ctx = talloc_stackframe(); |
1434 | 0 | struct regdb_create_subkey_context create_ctx; |
1435 | |
|
1436 | 0 | if (!regdb_key_exists(db, key)) { |
1437 | 0 | werr = WERR_NOT_FOUND; |
1438 | 0 | goto done; |
1439 | 0 | } |
1440 | | |
1441 | 0 | werr = regsubkey_ctr_init(mem_ctx, &subkeys); |
1442 | 0 | W_ERROR_NOT_OK_GOTO_DONE(werr); |
1443 | | |
1444 | 0 | werr = regdb_fetch_keys_internal(db, key, subkeys); |
1445 | 0 | W_ERROR_NOT_OK_GOTO_DONE(werr); |
1446 | | |
1447 | 0 | if (regsubkey_ctr_key_exists(subkeys, subkey)) { |
1448 | 0 | char *newkey; |
1449 | |
|
1450 | 0 | newkey = talloc_asprintf(mem_ctx, "%s\\%s", key, subkey); |
1451 | 0 | if (newkey == NULL) { |
1452 | 0 | werr = WERR_NOT_ENOUGH_MEMORY; |
1453 | 0 | goto done; |
1454 | 0 | } |
1455 | | |
1456 | 0 | if (regdb_key_exists(db, newkey)) { |
1457 | 0 | werr = WERR_OK; |
1458 | 0 | goto done; |
1459 | 0 | } |
1460 | 0 | } |
1461 | | |
1462 | 0 | talloc_free(subkeys); |
1463 | |
|
1464 | 0 | create_ctx.key = key; |
1465 | 0 | create_ctx.subkey = subkey; |
1466 | |
|
1467 | 0 | werr = regdb_trans_do(db, |
1468 | 0 | regdb_create_subkey_action, |
1469 | 0 | &create_ctx); |
1470 | |
|
1471 | 0 | done: |
1472 | 0 | talloc_free(mem_ctx); |
1473 | 0 | return werr; |
1474 | 0 | } |
1475 | | |
1476 | | static WERROR regdb_create_subkey(const char *key, const char *subkey) |
1477 | 0 | { |
1478 | 0 | return regdb_create_subkey_internal(regdb, key, subkey); |
1479 | 0 | } |
1480 | | |
1481 | | /** |
1482 | | * create a base key |
1483 | | */ |
1484 | | |
1485 | | struct regdb_create_basekey_context { |
1486 | | const char *key; |
1487 | | }; |
1488 | | |
1489 | | static NTSTATUS regdb_create_basekey_action(struct db_context *db, |
1490 | | void *private_data) |
1491 | 0 | { |
1492 | 0 | WERROR werr; |
1493 | 0 | struct regdb_create_basekey_context *create_ctx; |
1494 | |
|
1495 | 0 | create_ctx = (struct regdb_create_basekey_context *)private_data; |
1496 | |
|
1497 | 0 | werr = regdb_store_subkey_list(db, NULL, create_ctx->key); |
1498 | |
|
1499 | 0 | return werror_to_ntstatus(werr); |
1500 | 0 | } |
1501 | | |
1502 | | static WERROR regdb_create_basekey(struct db_context *db, const char *key) |
1503 | 0 | { |
1504 | 0 | WERROR werr; |
1505 | 0 | struct regdb_create_subkey_context create_ctx; |
1506 | |
|
1507 | 0 | create_ctx.key = key; |
1508 | |
|
1509 | 0 | werr = regdb_trans_do(db, |
1510 | 0 | regdb_create_basekey_action, |
1511 | 0 | &create_ctx); |
1512 | |
|
1513 | 0 | return werr; |
1514 | 0 | } |
1515 | | |
1516 | | /** |
1517 | | * create a subkey of a given key |
1518 | | */ |
1519 | | |
1520 | | struct regdb_delete_subkey_context { |
1521 | | const char *key; |
1522 | | const char *subkey; |
1523 | | const char *path; |
1524 | | bool lazy; |
1525 | | }; |
1526 | | |
1527 | | static NTSTATUS regdb_delete_subkey_action(struct db_context *db, |
1528 | | void *private_data) |
1529 | 0 | { |
1530 | 0 | WERROR werr; |
1531 | 0 | struct regdb_delete_subkey_context *delete_ctx; |
1532 | 0 | struct regsubkey_ctr *subkeys; |
1533 | 0 | TALLOC_CTX *mem_ctx = talloc_stackframe(); |
1534 | |
|
1535 | 0 | delete_ctx = (struct regdb_delete_subkey_context *)private_data; |
1536 | |
|
1537 | 0 | werr = regdb_delete_key_lists(db, delete_ctx->path); |
1538 | 0 | W_ERROR_NOT_OK_GOTO_DONE(werr); |
1539 | | |
1540 | 0 | if (delete_ctx->lazy) { |
1541 | 0 | goto done; |
1542 | 0 | } |
1543 | | |
1544 | 0 | werr = regsubkey_ctr_init(mem_ctx, &subkeys); |
1545 | 0 | W_ERROR_NOT_OK_GOTO_DONE(werr); |
1546 | | |
1547 | 0 | werr = regdb_fetch_keys_internal(db, delete_ctx->key, subkeys); |
1548 | 0 | W_ERROR_NOT_OK_GOTO_DONE(werr); |
1549 | | |
1550 | 0 | werr = regsubkey_ctr_delkey(subkeys, delete_ctx->subkey); |
1551 | 0 | W_ERROR_NOT_OK_GOTO_DONE(werr); |
1552 | | |
1553 | 0 | werr = regdb_store_keys_internal2(db, delete_ctx->key, subkeys); |
1554 | 0 | if (!W_ERROR_IS_OK(werr)) { |
1555 | 0 | DEBUG(0, (__location__ " failed to store new subkey_list for " |
1556 | 0 | "parent key %s: %s\n", delete_ctx->key, |
1557 | 0 | win_errstr(werr))); |
1558 | 0 | } |
1559 | |
|
1560 | 0 | done: |
1561 | 0 | talloc_free(mem_ctx); |
1562 | 0 | return werror_to_ntstatus(werr); |
1563 | 0 | } |
1564 | | |
1565 | | static WERROR regdb_delete_subkey(const char *key, const char *subkey, bool lazy) |
1566 | 0 | { |
1567 | 0 | WERROR werr; |
1568 | 0 | char *path; |
1569 | 0 | struct regdb_delete_subkey_context delete_ctx; |
1570 | 0 | TALLOC_CTX *mem_ctx = talloc_stackframe(); |
1571 | |
|
1572 | 0 | if (!regdb_key_exists(regdb, key)) { |
1573 | 0 | werr = WERR_NOT_FOUND; |
1574 | 0 | goto done; |
1575 | 0 | } |
1576 | | |
1577 | 0 | path = talloc_asprintf(mem_ctx, "%s\\%s", key, subkey); |
1578 | 0 | if (path == NULL) { |
1579 | 0 | werr = WERR_NOT_ENOUGH_MEMORY; |
1580 | 0 | goto done; |
1581 | 0 | } |
1582 | | |
1583 | 0 | if (!regdb_key_exists(regdb, path)) { |
1584 | 0 | werr = WERR_OK; |
1585 | 0 | goto done; |
1586 | 0 | } |
1587 | | |
1588 | 0 | delete_ctx.key = key; |
1589 | 0 | delete_ctx.subkey = subkey; |
1590 | 0 | delete_ctx.path = path; |
1591 | 0 | delete_ctx.lazy = lazy; |
1592 | |
|
1593 | 0 | werr = regdb_trans_do(regdb, |
1594 | 0 | regdb_delete_subkey_action, |
1595 | 0 | &delete_ctx); |
1596 | |
|
1597 | 0 | done: |
1598 | 0 | talloc_free(mem_ctx); |
1599 | 0 | return werr; |
1600 | 0 | } |
1601 | | |
1602 | | static TDB_DATA regdb_fetch_key_internal(struct db_context *db, |
1603 | | TALLOC_CTX *mem_ctx, const char *key) |
1604 | 0 | { |
1605 | 0 | char *path = NULL; |
1606 | 0 | TDB_DATA data; |
1607 | 0 | NTSTATUS status; |
1608 | |
|
1609 | 0 | path = normalize_reg_path(mem_ctx, key); |
1610 | 0 | if (!path) { |
1611 | 0 | return make_tdb_data(NULL, 0); |
1612 | 0 | } |
1613 | | |
1614 | 0 | status = dbwrap_fetch_bystring(db, mem_ctx, path, &data); |
1615 | 0 | if (!NT_STATUS_IS_OK(status)) { |
1616 | 0 | data = tdb_null; |
1617 | 0 | } |
1618 | |
|
1619 | 0 | TALLOC_FREE(path); |
1620 | 0 | return data; |
1621 | 0 | } |
1622 | | |
1623 | | |
1624 | | /** |
1625 | | * Check for the existence of a key. |
1626 | | * |
1627 | | * Existence of a key is authoritatively defined by |
1628 | | * the existence of the record that contains the list |
1629 | | * of its subkeys. |
1630 | | * |
1631 | | * Return false, if the record does not match the correct |
1632 | | * structure of an initial 4-byte counter and then a |
1633 | | * list of the corresponding number of zero-terminated |
1634 | | * strings. |
1635 | | */ |
1636 | | static bool regdb_key_exists(struct db_context *db, const char *key) |
1637 | 0 | { |
1638 | 0 | TALLOC_CTX *mem_ctx = talloc_stackframe(); |
1639 | 0 | TDB_DATA value; |
1640 | 0 | bool ret = false; |
1641 | 0 | char *path; |
1642 | 0 | uint32_t buflen; |
1643 | 0 | const char *buf; |
1644 | 0 | uint32_t num_items, i; |
1645 | 0 | int32_t len; |
1646 | |
|
1647 | 0 | if (key == NULL) { |
1648 | 0 | goto done; |
1649 | 0 | } |
1650 | | |
1651 | 0 | path = normalize_reg_path(mem_ctx, key); |
1652 | 0 | if (path == NULL) { |
1653 | 0 | DEBUG(0, ("out of memory! (talloc failed)\n")); |
1654 | 0 | goto done; |
1655 | 0 | } |
1656 | | |
1657 | 0 | if (*path == '\0') { |
1658 | 0 | goto done; |
1659 | 0 | } |
1660 | | |
1661 | 0 | value = regdb_fetch_key_internal(db, mem_ctx, path); |
1662 | 0 | if (value.dptr == NULL) { |
1663 | 0 | goto done; |
1664 | 0 | } |
1665 | | |
1666 | 0 | if (value.dsize == 0) { |
1667 | 0 | DEBUG(10, ("regdb_key_exists: subkeylist-record for key " |
1668 | 0 | "[%s] is empty: Could be a deleted record in a " |
1669 | 0 | "clustered (ctdb) environment?\n", |
1670 | 0 | path)); |
1671 | 0 | goto done; |
1672 | 0 | } |
1673 | | |
1674 | 0 | len = tdb_unpack(value.dptr, value.dsize, "d", &num_items); |
1675 | 0 | if (len == (int32_t)-1) { |
1676 | 0 | DEBUG(1, ("regdb_key_exists: ERROR: subkeylist-record for key " |
1677 | 0 | "[%s] is invalid: Could not parse initial 4-byte " |
1678 | 0 | "counter. record data length is %u.\n", |
1679 | 0 | path, (unsigned int)value.dsize)); |
1680 | 0 | goto done; |
1681 | 0 | } |
1682 | | |
1683 | | /* |
1684 | | * Note: the tdb_unpack check above implies that len <= value.dsize |
1685 | | */ |
1686 | 0 | buflen = value.dsize - len; |
1687 | 0 | buf = (const char *)value.dptr + len; |
1688 | |
|
1689 | 0 | for (i = 0; i < num_items; i++) { |
1690 | 0 | if (buflen == 0) { |
1691 | 0 | break; |
1692 | 0 | } |
1693 | 0 | len = strnlen(buf, buflen) + 1; |
1694 | 0 | if (buflen < len) { |
1695 | 0 | DEBUG(1, ("regdb_key_exists: ERROR: subkeylist-record " |
1696 | 0 | "for key [%s] is corrupt: %u items expected, " |
1697 | 0 | "item number %u is not zero terminated.\n", |
1698 | 0 | path, num_items, i+1)); |
1699 | 0 | goto done; |
1700 | 0 | } |
1701 | | |
1702 | 0 | buf += len; |
1703 | 0 | buflen -= len; |
1704 | 0 | } |
1705 | | |
1706 | 0 | if (buflen > 0) { |
1707 | 0 | DEBUG(1, ("regdb_key_exists: ERROR: subkeylist-record for key " |
1708 | 0 | "[%s] is corrupt: %u items expected and found, but " |
1709 | 0 | "the record contains additional %u bytes\n", |
1710 | 0 | path, num_items, buflen)); |
1711 | 0 | goto done; |
1712 | 0 | } |
1713 | | |
1714 | 0 | if (i < num_items) { |
1715 | 0 | DEBUG(1, ("regdb_key_exists: ERROR: subkeylist-record for key " |
1716 | 0 | "[%s] is corrupt: %u items expected, but only %u " |
1717 | 0 | "items found.\n", |
1718 | 0 | path, num_items, i+1)); |
1719 | 0 | goto done; |
1720 | 0 | } |
1721 | | |
1722 | 0 | ret = true; |
1723 | |
|
1724 | 0 | done: |
1725 | 0 | TALLOC_FREE(mem_ctx); |
1726 | 0 | return ret; |
1727 | 0 | } |
1728 | | |
1729 | | |
1730 | | /*********************************************************************** |
1731 | | Retrieve an array of strings containing subkeys. Memory should be |
1732 | | released by the caller. |
1733 | | ***********************************************************************/ |
1734 | | |
1735 | | static WERROR regdb_fetch_keys_internal(struct db_context *db, const char *key, |
1736 | | struct regsubkey_ctr *ctr) |
1737 | 0 | { |
1738 | 0 | WERROR werr; |
1739 | 0 | uint32_t num_items; |
1740 | 0 | uint8_t *buf; |
1741 | 0 | uint32_t buflen, len; |
1742 | 0 | uint32_t i; |
1743 | 0 | fstring subkeyname; |
1744 | 0 | TALLOC_CTX *frame = talloc_stackframe(); |
1745 | 0 | TDB_DATA value; |
1746 | 0 | int seqnum[2], count; |
1747 | |
|
1748 | 0 | DEBUG(11,("regdb_fetch_keys: Enter key => [%s]\n", key ? key : "NULL")); |
1749 | |
|
1750 | 0 | if (!regdb_key_exists(db, key)) { |
1751 | 0 | DEBUG(10, ("key [%s] not found\n", key)); |
1752 | 0 | werr = WERR_NOT_FOUND; |
1753 | 0 | goto done; |
1754 | 0 | } |
1755 | | |
1756 | 0 | werr = regsubkey_ctr_reinit(ctr); |
1757 | 0 | W_ERROR_NOT_OK_GOTO_DONE(werr); |
1758 | | |
1759 | 0 | count = 0; |
1760 | 0 | ZERO_STRUCT(value); |
1761 | 0 | seqnum[0] = dbwrap_get_seqnum(db); |
1762 | |
|
1763 | 0 | do { |
1764 | 0 | count++; |
1765 | 0 | TALLOC_FREE(value.dptr); |
1766 | 0 | value = regdb_fetch_key_internal(db, frame, key); |
1767 | 0 | seqnum[count % 2] = dbwrap_get_seqnum(db); |
1768 | |
|
1769 | 0 | } while (seqnum[0] != seqnum[1]); |
1770 | |
|
1771 | 0 | if (count > 1) { |
1772 | 0 | DEBUG(5, ("regdb_fetch_keys_internal: it took %d attempts to " |
1773 | 0 | "fetch key '%s' with constant seqnum\n", |
1774 | 0 | count, key)); |
1775 | 0 | } |
1776 | |
|
1777 | 0 | werr = regsubkey_ctr_set_seqnum(ctr, seqnum[0]); |
1778 | 0 | if (!W_ERROR_IS_OK(werr)) { |
1779 | 0 | goto done; |
1780 | 0 | } |
1781 | | |
1782 | 0 | if (value.dsize == 0 || value.dptr == NULL) { |
1783 | 0 | DEBUG(10, ("regdb_fetch_keys: no subkeys found for key [%s]\n", |
1784 | 0 | key)); |
1785 | 0 | goto done; |
1786 | 0 | } |
1787 | | |
1788 | 0 | buf = value.dptr; |
1789 | 0 | buflen = value.dsize; |
1790 | 0 | len = tdb_unpack( buf, buflen, "d", &num_items); |
1791 | 0 | if (len == (uint32_t)-1) { |
1792 | 0 | werr = WERR_NOT_FOUND; |
1793 | 0 | goto done; |
1794 | 0 | } |
1795 | | |
1796 | 0 | for (i=0; i<num_items; i++) { |
1797 | 0 | int this_len; |
1798 | |
|
1799 | 0 | this_len = tdb_unpack(buf+len, buflen-len, "f", subkeyname); |
1800 | 0 | if (this_len == -1) { |
1801 | 0 | DBG_WARNING("Invalid registry data, " |
1802 | 0 | "tdb_unpack failed\n"); |
1803 | 0 | werr = WERR_INTERNAL_DB_CORRUPTION; |
1804 | 0 | goto done; |
1805 | 0 | } |
1806 | 0 | len += this_len; |
1807 | 0 | if (len < this_len) { |
1808 | 0 | DBG_WARNING("Invalid registry data, " |
1809 | 0 | "integer overflow\n"); |
1810 | 0 | werr = WERR_INTERNAL_DB_CORRUPTION; |
1811 | 0 | goto done; |
1812 | 0 | } |
1813 | | |
1814 | 0 | werr = regsubkey_ctr_addkey(ctr, subkeyname); |
1815 | 0 | if (!W_ERROR_IS_OK(werr)) { |
1816 | 0 | DEBUG(5, ("regdb_fetch_keys: regsubkey_ctr_addkey " |
1817 | 0 | "failed: %s\n", win_errstr(werr))); |
1818 | 0 | num_items = 0; |
1819 | 0 | goto done; |
1820 | 0 | } |
1821 | 0 | } |
1822 | | |
1823 | 0 | DEBUG(11,("regdb_fetch_keys: Exit [%d] items\n", num_items)); |
1824 | |
|
1825 | 0 | done: |
1826 | 0 | TALLOC_FREE(frame); |
1827 | 0 | return werr; |
1828 | 0 | } |
1829 | | |
1830 | | static int regdb_fetch_keys(const char *key, struct regsubkey_ctr *ctr) |
1831 | 0 | { |
1832 | 0 | WERROR werr; |
1833 | |
|
1834 | 0 | werr = regdb_fetch_keys_internal(regdb, key, ctr); |
1835 | 0 | if (!W_ERROR_IS_OK(werr)) { |
1836 | 0 | return -1; |
1837 | 0 | } |
1838 | | |
1839 | 0 | return regsubkey_ctr_numkeys(ctr); |
1840 | 0 | } |
1841 | | |
1842 | | /**************************************************************************** |
1843 | | Unpack a list of registry values frem the TDB |
1844 | | ***************************************************************************/ |
1845 | | |
1846 | | static int regdb_unpack_values(struct regval_ctr *values, |
1847 | | uint8_t *buf, |
1848 | | size_t buflen) |
1849 | 0 | { |
1850 | 0 | int this_len; |
1851 | 0 | size_t len = 0; |
1852 | 0 | uint32_t type; |
1853 | 0 | fstring valuename; |
1854 | 0 | uint32_t size; |
1855 | 0 | uint8_t *data_p; |
1856 | 0 | uint32_t num_values = 0; |
1857 | 0 | uint32_t i; |
1858 | | |
1859 | | /* loop and unpack the rest of the registry values */ |
1860 | |
|
1861 | 0 | this_len = tdb_unpack(buf, buflen, "d", &num_values); |
1862 | 0 | if (this_len == -1) { |
1863 | 0 | DBG_WARNING("Invalid registry data, " |
1864 | 0 | "tdb_unpack failed\n"); |
1865 | 0 | return -1; |
1866 | 0 | } |
1867 | 0 | len = this_len; |
1868 | |
|
1869 | 0 | for ( i=0; i<num_values; i++ ) { |
1870 | | /* unpack the next regval */ |
1871 | |
|
1872 | 0 | type = REG_NONE; |
1873 | 0 | size = 0; |
1874 | 0 | data_p = NULL; |
1875 | 0 | valuename[0] = '\0'; |
1876 | 0 | this_len = tdb_unpack(buf+len, buflen-len, "fdB", |
1877 | 0 | valuename, |
1878 | 0 | &type, |
1879 | 0 | &size, |
1880 | 0 | &data_p); |
1881 | 0 | if (this_len == -1) { |
1882 | 0 | DBG_WARNING("Invalid registry data, " |
1883 | 0 | "tdb_unpack failed\n"); |
1884 | 0 | return -1; |
1885 | 0 | } |
1886 | 0 | len += this_len; |
1887 | 0 | if (len < (size_t)this_len) { |
1888 | 0 | DBG_WARNING("Invalid registry data, " |
1889 | 0 | "integer overflow\n"); |
1890 | 0 | return -1; |
1891 | 0 | } |
1892 | | |
1893 | 0 | regval_ctr_addvalue(values, valuename, type, |
1894 | 0 | (uint8_t *)data_p, size); |
1895 | 0 | SAFE_FREE(data_p); /* 'B' option to tdb_unpack does a malloc() */ |
1896 | |
|
1897 | 0 | DEBUG(10, ("regdb_unpack_values: value[%d]: name[%s] len[%d]\n", |
1898 | 0 | i, valuename, size)); |
1899 | 0 | } |
1900 | | |
1901 | 0 | return len; |
1902 | 0 | } |
1903 | | |
1904 | | /**************************************************************************** |
1905 | | Pack all values in all printer keys |
1906 | | ***************************************************************************/ |
1907 | | |
1908 | | static int regdb_pack_values(struct regval_ctr *values, uint8_t *buf, int buflen) |
1909 | 0 | { |
1910 | 0 | int len = 0; |
1911 | 0 | int i; |
1912 | 0 | struct regval_blob *val; |
1913 | 0 | int num_values; |
1914 | |
|
1915 | 0 | if ( !values ) |
1916 | 0 | return 0; |
1917 | | |
1918 | 0 | num_values = regval_ctr_numvals( values ); |
1919 | | |
1920 | | /* pack the number of values first */ |
1921 | |
|
1922 | 0 | len += tdb_pack( buf+len, buflen-len, "d", num_values ); |
1923 | | |
1924 | | /* loop over all values */ |
1925 | |
|
1926 | 0 | for ( i=0; i<num_values; i++ ) { |
1927 | 0 | val = regval_ctr_specific_value( values, i ); |
1928 | 0 | len += tdb_pack(buf+len, buflen-len, "fdB", |
1929 | 0 | regval_name(val), |
1930 | 0 | regval_type(val), |
1931 | 0 | regval_size(val), |
1932 | 0 | regval_data_p(val) ); |
1933 | 0 | } |
1934 | |
|
1935 | 0 | return len; |
1936 | 0 | } |
1937 | | |
1938 | | /*********************************************************************** |
1939 | | Retrieve an array of strings containing subkeys. Memory should be |
1940 | | released by the caller. |
1941 | | ***********************************************************************/ |
1942 | | |
1943 | | static int regdb_fetch_values_internal(struct db_context *db, const char* key, |
1944 | | struct regval_ctr *values) |
1945 | 0 | { |
1946 | 0 | char *keystr = NULL; |
1947 | 0 | TALLOC_CTX *ctx = talloc_stackframe(); |
1948 | 0 | int ret = 0; |
1949 | 0 | TDB_DATA value; |
1950 | 0 | WERROR werr; |
1951 | 0 | int seqnum[2], count; |
1952 | |
|
1953 | 0 | DEBUG(10,("regdb_fetch_values: Looking for values of key [%s]\n", key)); |
1954 | |
|
1955 | 0 | if (!regdb_key_exists(db, key)) { |
1956 | 0 | DEBUG(10, ("regb_fetch_values: key [%s] does not exist\n", |
1957 | 0 | key)); |
1958 | 0 | ret = -1; |
1959 | 0 | goto done; |
1960 | 0 | } |
1961 | | |
1962 | 0 | keystr = talloc_asprintf(ctx, "%s\\%s", REG_VALUE_PREFIX, key); |
1963 | 0 | if (!keystr) { |
1964 | 0 | goto done; |
1965 | 0 | } |
1966 | | |
1967 | 0 | ZERO_STRUCT(value); |
1968 | 0 | count = 0; |
1969 | 0 | seqnum[0] = dbwrap_get_seqnum(db); |
1970 | |
|
1971 | 0 | do { |
1972 | 0 | count++; |
1973 | 0 | TALLOC_FREE(value.dptr); |
1974 | 0 | value = regdb_fetch_key_internal(db, ctx, keystr); |
1975 | 0 | seqnum[count % 2] = dbwrap_get_seqnum(db); |
1976 | 0 | } while (seqnum[0] != seqnum[1]); |
1977 | |
|
1978 | 0 | if (count > 1) { |
1979 | 0 | DEBUG(5, ("regdb_fetch_values_internal: it took %d attempts " |
1980 | 0 | "to fetch key '%s' with constant seqnum\n", |
1981 | 0 | count, key)); |
1982 | 0 | } |
1983 | |
|
1984 | 0 | werr = regval_ctr_set_seqnum(values, seqnum[0]); |
1985 | 0 | if (!W_ERROR_IS_OK(werr)) { |
1986 | 0 | goto done; |
1987 | 0 | } |
1988 | | |
1989 | 0 | if (!value.dptr) { |
1990 | | /* all keys have zero values by default */ |
1991 | 0 | goto done; |
1992 | 0 | } |
1993 | | |
1994 | 0 | ret = regdb_unpack_values(values, value.dptr, value.dsize); |
1995 | 0 | if (ret == -1) { |
1996 | 0 | DBG_WARNING("regdb_unpack_values failed\n"); |
1997 | 0 | } |
1998 | |
|
1999 | 0 | ret = regval_ctr_numvals(values); |
2000 | |
|
2001 | 0 | done: |
2002 | 0 | TALLOC_FREE(ctx); |
2003 | 0 | return ret; |
2004 | 0 | } |
2005 | | |
2006 | | static int regdb_fetch_values(const char* key, struct regval_ctr *values) |
2007 | 0 | { |
2008 | 0 | return regdb_fetch_values_internal(regdb, key, values); |
2009 | 0 | } |
2010 | | |
2011 | | static NTSTATUS regdb_store_values_internal(struct db_context *db, |
2012 | | const char *key, |
2013 | | struct regval_ctr *values) |
2014 | 0 | { |
2015 | 0 | TDB_DATA old_data, data; |
2016 | 0 | char *keystr = NULL; |
2017 | 0 | TALLOC_CTX *ctx = talloc_stackframe(); |
2018 | 0 | int len; |
2019 | 0 | NTSTATUS status; |
2020 | 0 | WERROR werr; |
2021 | |
|
2022 | 0 | DEBUG(10,("regdb_store_values: Looking for values of key [%s]\n", key)); |
2023 | |
|
2024 | 0 | if (!regdb_key_exists(db, key)) { |
2025 | 0 | status = NT_STATUS_NOT_FOUND; |
2026 | 0 | goto done; |
2027 | 0 | } |
2028 | | |
2029 | 0 | if (regval_ctr_numvals(values) == 0) { |
2030 | 0 | werr = regdb_delete_values(db, key); |
2031 | 0 | if (!W_ERROR_IS_OK(werr)) { |
2032 | 0 | status = werror_to_ntstatus(werr); |
2033 | 0 | goto done; |
2034 | 0 | } |
2035 | | |
2036 | | /* |
2037 | | * update the seqnum in the cache to prevent the next read |
2038 | | * from going to disk |
2039 | | */ |
2040 | 0 | werr = regval_ctr_set_seqnum(values, dbwrap_get_seqnum(db)); |
2041 | 0 | status = werror_to_ntstatus(werr); |
2042 | 0 | goto done; |
2043 | 0 | } |
2044 | | |
2045 | 0 | ZERO_STRUCT(data); |
2046 | |
|
2047 | 0 | len = regdb_pack_values(values, data.dptr, data.dsize); |
2048 | 0 | if (len <= 0) { |
2049 | 0 | DEBUG(0,("regdb_store_values: unable to pack values. len <= 0\n")); |
2050 | 0 | status = NT_STATUS_UNSUCCESSFUL; |
2051 | 0 | goto done; |
2052 | 0 | } |
2053 | | |
2054 | 0 | data.dptr = talloc_array(ctx, uint8_t, len); |
2055 | 0 | data.dsize = len; |
2056 | |
|
2057 | 0 | len = regdb_pack_values(values, data.dptr, data.dsize); |
2058 | |
|
2059 | 0 | SMB_ASSERT( len == data.dsize ); |
2060 | | |
2061 | 0 | keystr = talloc_asprintf(ctx, "%s\\%s", REG_VALUE_PREFIX, key ); |
2062 | 0 | if (!keystr) { |
2063 | 0 | status = NT_STATUS_NO_MEMORY; |
2064 | 0 | goto done; |
2065 | 0 | } |
2066 | 0 | keystr = normalize_reg_path(ctx, keystr); |
2067 | 0 | if (!keystr) { |
2068 | 0 | status = NT_STATUS_NO_MEMORY; |
2069 | 0 | goto done; |
2070 | 0 | } |
2071 | | |
2072 | 0 | status = dbwrap_fetch_bystring(db, ctx, keystr, &old_data); |
2073 | |
|
2074 | 0 | if (NT_STATUS_IS_OK(status) |
2075 | 0 | && (old_data.dptr != NULL) |
2076 | 0 | && (old_data.dsize == data.dsize) |
2077 | 0 | && (memcmp(old_data.dptr, data.dptr, data.dsize) == 0)) |
2078 | 0 | { |
2079 | 0 | status = NT_STATUS_OK; |
2080 | 0 | goto done; |
2081 | 0 | } |
2082 | | |
2083 | 0 | status = dbwrap_trans_store_bystring(db, keystr, data, TDB_REPLACE); |
2084 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2085 | 0 | DEBUG(0, ("regdb_store_values_internal: error storing: %s\n", nt_errstr(status))); |
2086 | 0 | goto done; |
2087 | 0 | } |
2088 | | |
2089 | | /* |
2090 | | * update the seqnum in the cache to prevent the next read |
2091 | | * from going to disk |
2092 | | */ |
2093 | 0 | werr = regval_ctr_set_seqnum(values, dbwrap_get_seqnum(db)); |
2094 | 0 | status = werror_to_ntstatus(werr); |
2095 | |
|
2096 | 0 | done: |
2097 | 0 | TALLOC_FREE(ctx); |
2098 | 0 | return status; |
2099 | 0 | } |
2100 | | |
2101 | | struct regdb_store_values_ctx { |
2102 | | const char *key; |
2103 | | struct regval_ctr *values; |
2104 | | }; |
2105 | | |
2106 | | static NTSTATUS regdb_store_values_action(struct db_context *db, |
2107 | | void *private_data) |
2108 | 0 | { |
2109 | 0 | NTSTATUS status; |
2110 | 0 | struct regdb_store_values_ctx *ctx = |
2111 | 0 | (struct regdb_store_values_ctx *)private_data; |
2112 | |
|
2113 | 0 | status = regdb_store_values_internal(db, ctx->key, ctx->values); |
2114 | |
|
2115 | 0 | return status; |
2116 | 0 | } |
2117 | | |
2118 | | static bool regdb_store_values(const char *key, struct regval_ctr *values) |
2119 | 0 | { |
2120 | 0 | WERROR werr; |
2121 | 0 | struct regdb_store_values_ctx ctx; |
2122 | |
|
2123 | 0 | ctx.key = key; |
2124 | 0 | ctx.values = values; |
2125 | |
|
2126 | 0 | werr = regdb_trans_do(regdb, regdb_store_values_action, &ctx); |
2127 | |
|
2128 | 0 | return W_ERROR_IS_OK(werr); |
2129 | 0 | } |
2130 | | |
2131 | | static WERROR regdb_get_secdesc(TALLOC_CTX *mem_ctx, const char *key, |
2132 | | struct security_descriptor **psecdesc) |
2133 | 0 | { |
2134 | 0 | char *tdbkey; |
2135 | 0 | TDB_DATA data; |
2136 | 0 | NTSTATUS status; |
2137 | 0 | TALLOC_CTX *tmp_ctx = talloc_stackframe(); |
2138 | 0 | WERROR err = WERR_OK; |
2139 | |
|
2140 | 0 | DEBUG(10, ("regdb_get_secdesc: Getting secdesc of key [%s]\n", key)); |
2141 | |
|
2142 | 0 | if (!regdb_key_exists(regdb, key)) { |
2143 | 0 | err = WERR_FILE_NOT_FOUND; |
2144 | 0 | goto done; |
2145 | 0 | } |
2146 | | |
2147 | 0 | tdbkey = talloc_asprintf(tmp_ctx, "%s\\%s", REG_SECDESC_PREFIX, key); |
2148 | 0 | if (tdbkey == NULL) { |
2149 | 0 | err = WERR_NOT_ENOUGH_MEMORY; |
2150 | 0 | goto done; |
2151 | 0 | } |
2152 | | |
2153 | 0 | tdbkey = normalize_reg_path(tmp_ctx, tdbkey); |
2154 | 0 | if (tdbkey == NULL) { |
2155 | 0 | err = WERR_NOT_ENOUGH_MEMORY; |
2156 | 0 | goto done; |
2157 | 0 | } |
2158 | | |
2159 | 0 | status = dbwrap_fetch_bystring(regdb, tmp_ctx, tdbkey, &data); |
2160 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2161 | 0 | err = WERR_FILE_NOT_FOUND; |
2162 | 0 | goto done; |
2163 | 0 | } |
2164 | | |
2165 | 0 | status = unmarshall_sec_desc(mem_ctx, (uint8_t *)data.dptr, data.dsize, |
2166 | 0 | psecdesc); |
2167 | |
|
2168 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) { |
2169 | 0 | err = WERR_NOT_ENOUGH_MEMORY; |
2170 | 0 | } else if (!NT_STATUS_IS_OK(status)) { |
2171 | 0 | err = WERR_REGISTRY_CORRUPT; |
2172 | 0 | } |
2173 | |
|
2174 | 0 | done: |
2175 | 0 | TALLOC_FREE(tmp_ctx); |
2176 | 0 | return err; |
2177 | 0 | } |
2178 | | |
2179 | | struct regdb_set_secdesc_ctx { |
2180 | | const char *key; |
2181 | | struct security_descriptor *secdesc; |
2182 | | }; |
2183 | | |
2184 | | static NTSTATUS regdb_set_secdesc_action(struct db_context *db, |
2185 | | void *private_data) |
2186 | 0 | { |
2187 | 0 | char *tdbkey; |
2188 | 0 | NTSTATUS status; |
2189 | 0 | TDB_DATA tdbdata; |
2190 | 0 | struct regdb_set_secdesc_ctx *ctx = |
2191 | 0 | (struct regdb_set_secdesc_ctx *)private_data; |
2192 | 0 | TALLOC_CTX *frame = talloc_stackframe(); |
2193 | |
|
2194 | 0 | tdbkey = talloc_asprintf(frame, "%s\\%s", REG_SECDESC_PREFIX, ctx->key); |
2195 | 0 | if (tdbkey == NULL) { |
2196 | 0 | status = NT_STATUS_NO_MEMORY; |
2197 | 0 | goto done; |
2198 | 0 | } |
2199 | | |
2200 | 0 | tdbkey = normalize_reg_path(frame, tdbkey); |
2201 | 0 | if (tdbkey == NULL) { |
2202 | 0 | status = NT_STATUS_NO_MEMORY; |
2203 | 0 | goto done; |
2204 | 0 | } |
2205 | | |
2206 | 0 | if (ctx->secdesc == NULL) { |
2207 | | /* assuming a delete */ |
2208 | 0 | status = dbwrap_delete_bystring(db, tdbkey); |
2209 | 0 | goto done; |
2210 | 0 | } |
2211 | | |
2212 | 0 | status = marshall_sec_desc(frame, ctx->secdesc, &tdbdata.dptr, |
2213 | 0 | &tdbdata.dsize); |
2214 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2215 | 0 | goto done; |
2216 | 0 | } |
2217 | | |
2218 | 0 | status = dbwrap_store_bystring(db, tdbkey, tdbdata, 0); |
2219 | |
|
2220 | 0 | done: |
2221 | 0 | TALLOC_FREE(frame); |
2222 | 0 | return status; |
2223 | 0 | } |
2224 | | |
2225 | | static WERROR regdb_set_secdesc(const char *key, |
2226 | | struct security_descriptor *secdesc) |
2227 | 0 | { |
2228 | 0 | WERROR err; |
2229 | 0 | struct regdb_set_secdesc_ctx ctx; |
2230 | |
|
2231 | 0 | if (!regdb_key_exists(regdb, key)) { |
2232 | 0 | err = WERR_FILE_NOT_FOUND; |
2233 | 0 | goto done; |
2234 | 0 | } |
2235 | | |
2236 | 0 | ctx.key = key; |
2237 | 0 | ctx.secdesc = secdesc; |
2238 | |
|
2239 | 0 | err = regdb_trans_do(regdb, regdb_set_secdesc_action, &ctx); |
2240 | |
|
2241 | 0 | done: |
2242 | 0 | return err; |
2243 | 0 | } |
2244 | | |
2245 | | static bool regdb_subkeys_need_update(struct regsubkey_ctr *subkeys) |
2246 | 0 | { |
2247 | 0 | return (regdb_get_seqnum() != regsubkey_ctr_get_seqnum(subkeys)); |
2248 | 0 | } |
2249 | | |
2250 | | static bool regdb_values_need_update(struct regval_ctr *values) |
2251 | 0 | { |
2252 | 0 | return (regdb_get_seqnum() != regval_ctr_get_seqnum(values)); |
2253 | 0 | } |
2254 | | |
2255 | | /* |
2256 | | * Table of function pointers for default access |
2257 | | */ |
2258 | | |
2259 | | struct registry_ops regdb_ops = { |
2260 | | .fetch_subkeys = regdb_fetch_keys, |
2261 | | .fetch_values = regdb_fetch_values, |
2262 | | .store_subkeys = regdb_store_keys, |
2263 | | .store_values = regdb_store_values, |
2264 | | .create_subkey = regdb_create_subkey, |
2265 | | .delete_subkey = regdb_delete_subkey, |
2266 | | .get_secdesc = regdb_get_secdesc, |
2267 | | .set_secdesc = regdb_set_secdesc, |
2268 | | .subkeys_need_update = regdb_subkeys_need_update, |
2269 | | .values_need_update = regdb_values_need_update |
2270 | | }; |