Line data Source code
1 : /*
2 : Samba Unix/Linux CIFS implementation
3 :
4 : low level TDB/CTDB tool using the dbwrap interface
5 :
6 : Copyright (C) 2009 Michael Adam <obnox@samba.org>
7 : Copyright (C) 2011 Bjoern Baumbach <bb@sernet.de>
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include "system/filesys.h"
25 : #include "lib/cmdline/cmdline.h"
26 : #include "dbwrap/dbwrap.h"
27 : #include "dbwrap/dbwrap_open.h"
28 : #include "messages.h"
29 : #include "util_tdb.h"
30 : #include "cmdline_contexts.h"
31 : #include "lib/param/param.h"
32 :
33 : enum dbwrap_op { OP_FETCH, OP_STORE, OP_DELETE, OP_ERASE, OP_LISTKEYS,
34 : OP_EXISTS };
35 :
36 : enum dbwrap_type { TYPE_INT32, TYPE_UINT32, TYPE_STRING, TYPE_HEX, TYPE_NONE };
37 :
38 0 : static int dbwrap_tool_fetch_int32(struct db_context *db,
39 : const char *keyname,
40 : const char *data)
41 : {
42 : int32_t value;
43 : NTSTATUS status;
44 :
45 0 : status = dbwrap_fetch_int32_bystring(db, keyname, &value);
46 0 : if (!NT_STATUS_IS_OK(status)) {
47 0 : d_printf("Error fetching int32 from key '%s': %s\n",
48 : keyname, nt_errstr(status));
49 0 : return -1;
50 : }
51 0 : d_printf("%d\n", value);
52 :
53 0 : return 0;
54 : }
55 :
56 0 : static int dbwrap_tool_fetch_uint32(struct db_context *db,
57 : const char *keyname,
58 : const char *data)
59 : {
60 : uint32_t value;
61 : NTSTATUS ret;
62 :
63 0 : ret = dbwrap_fetch_uint32_bystring(db, keyname, &value);
64 0 : if (NT_STATUS_IS_OK(ret)) {
65 0 : d_printf("%u\n", value);
66 0 : return 0;
67 : } else {
68 0 : d_fprintf(stderr, "ERROR: could not fetch uint32 key '%s': "
69 : "%s\n", nt_errstr(ret), keyname);
70 0 : return -1;
71 : }
72 : }
73 :
74 0 : static int dbwrap_tool_fetch_string(struct db_context *db,
75 : const char *keyname,
76 : const char *data)
77 : {
78 : TDB_DATA tdbdata;
79 : NTSTATUS status;
80 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
81 : int ret;
82 :
83 0 : status = dbwrap_fetch_bystring(db, tmp_ctx, keyname, &tdbdata);
84 0 : if (NT_STATUS_IS_OK(status)) {
85 0 : d_printf("%-*.*s\n", (int)tdbdata.dsize, (int)tdbdata.dsize,
86 : tdbdata.dptr);
87 0 : ret = 0;
88 : } else {
89 0 : d_fprintf(stderr, "ERROR: could not fetch string key '%s': "
90 : "%s\n", nt_errstr(status), keyname);
91 0 : ret = -1;
92 : }
93 :
94 0 : talloc_free(tmp_ctx);
95 0 : return ret;
96 : }
97 :
98 0 : static int dbwrap_tool_fetch_hex(struct db_context *db,
99 : const char *keyname,
100 : const char *data)
101 : {
102 : TDB_DATA tdbdata;
103 : DATA_BLOB datablob;
104 : NTSTATUS status;
105 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
106 : char *hex_string;
107 : int ret;
108 :
109 0 : status = dbwrap_fetch_bystring(db, tmp_ctx, keyname, &tdbdata);
110 0 : if (NT_STATUS_IS_OK(status)) {
111 0 : datablob.data = tdbdata.dptr;
112 0 : datablob.length = tdbdata.dsize;
113 :
114 0 : hex_string = data_blob_hex_string_upper(tmp_ctx, &datablob);
115 0 : if (hex_string == NULL) {
116 0 : d_fprintf(stderr, "ERROR: could not get hex string "
117 : "from data blob\n");
118 0 : ret = -1;
119 : } else {
120 0 : d_printf("%s\n", hex_string);
121 0 : ret = 0;
122 : }
123 : } else {
124 0 : d_fprintf(stderr, "ERROR: could not fetch hex key '%s': "
125 : "%s\n", nt_errstr(status), keyname);
126 0 : ret = -1;
127 : }
128 :
129 0 : talloc_free(tmp_ctx);
130 0 : return ret;
131 : }
132 :
133 0 : static int dbwrap_tool_store_int32(struct db_context *db,
134 : const char *keyname,
135 : const char *data)
136 : {
137 : NTSTATUS status;
138 0 : int32_t value = (int32_t)strtol(data, NULL, 10);
139 :
140 0 : if (dbwrap_is_persistent(db)) {
141 0 : status = dbwrap_trans_store_int32_bystring(db, keyname, value);
142 : } else {
143 0 : status = dbwrap_store_int32_bystring(db, keyname, value);
144 : }
145 0 : if (!NT_STATUS_IS_OK(status)) {
146 0 : d_fprintf(stderr, "ERROR: could not store int32 key '%s': %s\n",
147 : keyname, nt_errstr(status));
148 0 : return -1;
149 : }
150 :
151 0 : return 0;
152 : }
153 :
154 2 : static int dbwrap_tool_store_uint32(struct db_context *db,
155 : const char *keyname,
156 : const char *data)
157 : {
158 : NTSTATUS status;
159 2 : uint32_t value = (uint32_t)strtol(data, NULL, 10);
160 :
161 2 : if (dbwrap_is_persistent(db)) {
162 2 : status = dbwrap_trans_store_uint32_bystring(db, keyname, value);
163 : } else {
164 0 : status = dbwrap_store_uint32_bystring(db, keyname, value);
165 : }
166 2 : if (!NT_STATUS_IS_OK(status)) {
167 0 : d_fprintf(stderr,
168 : "ERROR: could not store uint32 key '%s': %s\n",
169 : keyname, nt_errstr(status));
170 0 : return -1;
171 : }
172 :
173 2 : return 0;
174 : }
175 :
176 0 : static int dbwrap_tool_store_string(struct db_context *db,
177 : const char *keyname,
178 : const char *data)
179 : {
180 : NTSTATUS status;
181 : TDB_DATA tdbdata;
182 :
183 0 : tdbdata = string_term_tdb_data(data);
184 :
185 0 : if (dbwrap_is_persistent(db)) {
186 0 : status = dbwrap_trans_store_bystring(db, keyname,
187 : tdbdata,
188 : TDB_REPLACE);
189 : } else {
190 0 : status = dbwrap_store_bystring(db, keyname,
191 : tdbdata,
192 : TDB_REPLACE);
193 : }
194 0 : if (!NT_STATUS_IS_OK(status)) {
195 0 : d_fprintf(stderr,
196 : "ERROR: could not store string key '%s': %s\n",
197 : keyname, nt_errstr(status));
198 0 : return -1;
199 : }
200 :
201 0 : return 0;
202 : }
203 :
204 6 : static int dbwrap_tool_store_hex(struct db_context *db,
205 : const char *keyname,
206 : const char *data)
207 : {
208 : NTSTATUS status;
209 : DATA_BLOB datablob;
210 : TDB_DATA tdbdata;
211 6 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
212 :
213 6 : datablob = strhex_to_data_blob(tmp_ctx, data);
214 6 : if(strlen(data) > 0 && datablob.length == 0) {
215 0 : d_fprintf(stderr,
216 : "ERROR: could not convert hex string to data blob\n"
217 : " Not a valid hex string?\n");
218 0 : talloc_free(tmp_ctx);
219 0 : return -1;
220 : }
221 :
222 6 : tdbdata.dptr = (unsigned char *)datablob.data;
223 6 : tdbdata.dsize = datablob.length;
224 :
225 6 : if (dbwrap_is_persistent(db)) {
226 6 : status = dbwrap_trans_store_bystring(db, keyname,
227 : tdbdata,
228 : TDB_REPLACE);
229 : } else {
230 0 : status = dbwrap_store_bystring(db, keyname,
231 : tdbdata,
232 : TDB_REPLACE);
233 : }
234 6 : if (!NT_STATUS_IS_OK(status)) {
235 0 : d_fprintf(stderr,
236 : "ERROR: could not store string key '%s': %s\n",
237 : keyname, nt_errstr(status));
238 0 : talloc_free(tmp_ctx);
239 0 : return -1;
240 : }
241 :
242 6 : talloc_free(tmp_ctx);
243 6 : return 0;
244 : }
245 :
246 2 : static int dbwrap_tool_delete(struct db_context *db,
247 : const char *keyname,
248 : const char *data)
249 : {
250 : NTSTATUS status;
251 :
252 2 : if (dbwrap_is_persistent(db)) {
253 2 : status = dbwrap_trans_delete_bystring(db, keyname);
254 : } else {
255 0 : status = dbwrap_delete_bystring(db, keyname);
256 : }
257 :
258 2 : if (!NT_STATUS_IS_OK(status)) {
259 0 : d_fprintf(stderr, "ERROR deleting record %s : %s\n",
260 : keyname, nt_errstr(status));
261 0 : return -1;
262 : }
263 :
264 2 : return 0;
265 : }
266 :
267 0 : static int dbwrap_tool_exists(struct db_context *db,
268 : const char *keyname,
269 : const char *data)
270 : {
271 : bool result;
272 :
273 0 : result = dbwrap_exists(db, string_term_tdb_data(keyname));
274 :
275 0 : if (result) {
276 0 : d_fprintf(stdout, "Key %s exists\n", keyname);
277 : } else {
278 0 : d_fprintf(stdout, "Key %s does not exist\n", keyname);
279 : }
280 :
281 0 : return (result)?0:1;
282 : }
283 :
284 : /**
285 : * dbwrap_tool_erase: erase the whole data base
286 : * the keyname argument is not used.
287 : */
288 0 : static int dbwrap_tool_erase(struct db_context *db,
289 : const char *keyname,
290 : const char *data)
291 : {
292 : int ret;
293 :
294 0 : ret = dbwrap_wipe(db);
295 :
296 0 : if (ret != 0) {
297 0 : d_fprintf(stderr, "ERROR erasing the database\n");
298 0 : return -1;
299 : }
300 :
301 0 : return 0;
302 : }
303 :
304 0 : static int listkey_fn(struct db_record *rec, void *private_data)
305 : {
306 0 : TDB_DATA key = dbwrap_record_get_key(rec);
307 0 : size_t length = key.dsize;
308 0 : unsigned char *p = (unsigned char *)key.dptr;
309 :
310 0 : while (length--) {
311 0 : if (isprint(*p) && !strchr("\"\\", *p)) {
312 0 : d_printf("%c", *p);
313 : } else {
314 0 : d_printf("\\%02X", *p);
315 : }
316 0 : p++;
317 : }
318 :
319 0 : d_printf("\n");
320 :
321 0 : return 0;
322 : }
323 :
324 0 : static int dbwrap_tool_listkeys(struct db_context *db,
325 : const char *keyname,
326 : const char *data)
327 : {
328 : NTSTATUS status;
329 :
330 0 : status = dbwrap_traverse_read(db, listkey_fn, NULL, NULL);
331 :
332 0 : if (!NT_STATUS_IS_OK(status)) {
333 0 : d_fprintf(stderr, "ERROR listing db keys\n");
334 0 : return -1;
335 : }
336 :
337 0 : return 0;
338 : }
339 :
340 : struct dbwrap_op_dispatch_table {
341 : enum dbwrap_op op;
342 : enum dbwrap_type type;
343 : int (*cmd)(struct db_context *db,
344 : const char *keyname,
345 : const char *data);
346 : };
347 :
348 : struct dbwrap_op_dispatch_table dispatch_table[] = {
349 : { OP_FETCH, TYPE_INT32, dbwrap_tool_fetch_int32 },
350 : { OP_FETCH, TYPE_UINT32, dbwrap_tool_fetch_uint32 },
351 : { OP_FETCH, TYPE_STRING, dbwrap_tool_fetch_string },
352 : { OP_FETCH, TYPE_HEX, dbwrap_tool_fetch_hex },
353 : { OP_STORE, TYPE_INT32, dbwrap_tool_store_int32 },
354 : { OP_STORE, TYPE_UINT32, dbwrap_tool_store_uint32 },
355 : { OP_STORE, TYPE_STRING, dbwrap_tool_store_string },
356 : { OP_STORE, TYPE_HEX, dbwrap_tool_store_hex },
357 : { OP_DELETE, TYPE_INT32, dbwrap_tool_delete },
358 : { OP_ERASE, TYPE_INT32, dbwrap_tool_erase },
359 : { OP_LISTKEYS, TYPE_INT32, dbwrap_tool_listkeys },
360 : { OP_EXISTS, TYPE_STRING, dbwrap_tool_exists },
361 : { 0, 0, NULL },
362 : };
363 :
364 10 : int main(int argc, const char **argv)
365 : {
366 : struct tevent_context *evt_ctx;
367 : struct messaging_context *msg_ctx;
368 : struct db_context *db;
369 :
370 : uint16_t count;
371 :
372 : const char *dbname;
373 : const char *opname;
374 : enum dbwrap_op op;
375 10 : const char *keyname = "";
376 10 : const char *keytype = "int32";
377 : enum dbwrap_type type;
378 10 : const char *valuestr = "0";
379 10 : int persistent = 0;
380 10 : int non_persistent = 0;
381 10 : int tdb_flags = TDB_DEFAULT;
382 :
383 10 : TALLOC_CTX *mem_ctx = talloc_stackframe();
384 10 : struct loadparm_context *lp_ctx = NULL;
385 :
386 10 : int ret = 1;
387 : bool ok;
388 :
389 30 : struct poptOption popt_options[] = {
390 : POPT_AUTOHELP
391 10 : POPT_COMMON_SAMBA
392 : { "non-persistent", 0, POPT_ARG_NONE, &non_persistent, 0,
393 : "treat the database as non-persistent "
394 : "(CAVEAT: This mode might wipe your database!)",
395 : NULL },
396 : { "persistent", 0, POPT_ARG_NONE, &persistent, 0,
397 : "treat the database as persistent",
398 : NULL },
399 10 : POPT_COMMON_VERSION
400 : POPT_TABLEEND
401 : };
402 : int opt;
403 : const char **extra_argv;
404 10 : int extra_argc = 0;
405 : poptContext pc;
406 :
407 10 : smb_init_locale();
408 :
409 10 : setup_logging(argv[0], DEBUG_DEFAULT_STDERR);
410 :
411 10 : ok = samba_cmdline_init(mem_ctx,
412 : SAMBA_CMDLINE_CONFIG_CLIENT,
413 : false /* require_smbconf */);
414 10 : if (!ok) {
415 0 : DBG_ERR("Failed to init cmdline parser!\n");
416 0 : TALLOC_FREE(mem_ctx);
417 0 : exit(1);
418 : }
419 10 : lp_ctx = samba_cmdline_get_lp_ctx();
420 10 : lpcfg_set_cmdline(lp_ctx, "log level", "0");
421 :
422 10 : pc = samba_popt_get_context(getprogname(),
423 : argc,
424 : argv,
425 : popt_options,
426 : POPT_CONTEXT_KEEP_FIRST);
427 10 : if (!ok) {
428 0 : DBG_ERR("Failed to setup popt context!\n");
429 0 : TALLOC_FREE(mem_ctx);
430 0 : exit(1);
431 : }
432 :
433 10 : while ((opt = poptGetNextOpt(pc)) != -1) {
434 : switch (opt) {
435 0 : default:
436 0 : fprintf(stderr, "Invalid option %s: %s\n",
437 : poptBadOption(pc, 0), poptStrerror(opt));
438 0 : goto done;
439 : }
440 : }
441 :
442 : /* setup the remaining options for the main program to use */
443 10 : extra_argv = poptGetArgs(pc);
444 10 : if (extra_argv) {
445 10 : extra_argv++;
446 56 : while (extra_argv[extra_argc]) extra_argc++;
447 : }
448 :
449 10 : if ((extra_argc < 2) || (extra_argc > 5)) {
450 0 : d_fprintf(stderr,
451 : "USAGE: %s [options] <database> <op> [<key> [<type> "
452 : "[<value>]]]\n"
453 : " ops: fetch, store, delete, exists, "
454 : "erase, listkeys\n"
455 : " types: int32, uint32, string, hex\n",
456 : argv[0]);
457 0 : goto done;
458 : }
459 :
460 10 : if ((persistent + non_persistent) != 1) {
461 0 : d_fprintf(stderr, "ERROR: you must specify exactly one "
462 : "of --persistent and --non-persistent\n");
463 0 : goto done;
464 : }
465 10 : if (non_persistent == 1) {
466 0 : tdb_flags |= TDB_CLEAR_IF_FIRST;
467 : }
468 :
469 10 : dbname = extra_argv[0];
470 10 : opname = extra_argv[1];
471 :
472 10 : if (strcmp(opname, "store") == 0) {
473 8 : if (extra_argc != 5) {
474 0 : d_fprintf(stderr, "ERROR: operation 'store' requires "
475 : "value argument\n");
476 0 : goto done;
477 : }
478 8 : valuestr = extra_argv[4];
479 8 : keytype = extra_argv[3];
480 8 : keyname = extra_argv[2];
481 8 : op = OP_STORE;
482 2 : } else if (strcmp(opname, "fetch") == 0) {
483 0 : if (extra_argc != 4) {
484 0 : d_fprintf(stderr, "ERROR: operation 'fetch' requires "
485 : "type but not value argument\n");
486 0 : goto done;
487 : }
488 0 : op = OP_FETCH;
489 0 : keytype = extra_argv[3];
490 0 : keyname = extra_argv[2];
491 2 : } else if (strcmp(opname, "delete") == 0) {
492 2 : if (extra_argc != 3) {
493 0 : d_fprintf(stderr, "ERROR: operation 'delete' does "
494 : "not allow type nor value argument\n");
495 0 : goto done;
496 : }
497 2 : keyname = extra_argv[2];
498 2 : op = OP_DELETE;
499 0 : } else if (strcmp(opname, "erase") == 0) {
500 0 : if (extra_argc != 2) {
501 0 : d_fprintf(stderr, "ERROR: operation 'erase' does "
502 : "not take a key argument\n");
503 0 : goto done;
504 : }
505 0 : op = OP_ERASE;
506 0 : } else if (strcmp(opname, "listkeys") == 0) {
507 0 : if (extra_argc != 2) {
508 0 : d_fprintf(stderr, "ERROR: operation 'listkeys' does "
509 : "not take a key argument\n");
510 0 : goto done;
511 : }
512 0 : op = OP_LISTKEYS;
513 0 : } else if (strcmp(opname, "exists") == 0) {
514 0 : if (extra_argc != 3) {
515 0 : d_fprintf(stderr, "ERROR: operation 'exists' does "
516 : "not allow type nor value argument\n");
517 0 : goto done;
518 : }
519 0 : keyname = extra_argv[2];
520 0 : op = OP_EXISTS;
521 0 : keytype = "string";
522 : } else {
523 0 : d_fprintf(stderr,
524 : "ERROR: invalid op '%s' specified\n"
525 : " supported ops: fetch, store, delete, exists, "
526 : "erase, listkeys\n",
527 : opname);
528 0 : goto done;
529 : }
530 :
531 10 : if (strcmp(keytype, "int32") == 0) {
532 2 : type = TYPE_INT32;
533 8 : } else if (strcmp(keytype, "uint32") == 0) {
534 2 : type = TYPE_UINT32;
535 6 : } else if (strcmp(keytype, "string") == 0) {
536 0 : type = TYPE_STRING;
537 6 : } else if (strcmp(keytype, "hex") == 0) {
538 6 : type = TYPE_HEX;
539 0 : } else if (strcmp(keytype, "none") == 0) {
540 0 : type = TYPE_NONE;
541 : } else {
542 0 : d_fprintf(stderr, "ERROR: invalid type '%s' specified.\n"
543 : " supported types: int32, uint32, "
544 : "string, hex, none\n",
545 : keytype);
546 0 : goto done;
547 : }
548 :
549 10 : evt_ctx = samba_tevent_context_init(mem_ctx);
550 10 : if (evt_ctx == NULL) {
551 0 : d_fprintf(stderr, "ERROR: could not init event context\n");
552 0 : goto done;
553 : }
554 :
555 10 : msg_ctx = messaging_init(mem_ctx, evt_ctx);
556 10 : if (msg_ctx == NULL) {
557 0 : d_fprintf(stderr, "ERROR: could not init messaging context\n");
558 0 : goto done;
559 : }
560 :
561 10 : switch (op) {
562 10 : case OP_FETCH:
563 : case OP_STORE:
564 : case OP_DELETE:
565 : case OP_ERASE:
566 : case OP_LISTKEYS:
567 : case OP_EXISTS:
568 10 : db = db_open(mem_ctx, dbname, 0, tdb_flags, O_RDWR | O_CREAT,
569 : 0644, DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
570 10 : if (db == NULL) {
571 0 : d_fprintf(stderr, "ERROR: could not open dbname\n");
572 0 : goto done;
573 : }
574 10 : break;
575 0 : default:
576 0 : db = NULL;
577 0 : break;
578 : }
579 :
580 78 : for (count = 0; dispatch_table[count].cmd != NULL; count++) {
581 78 : if ((op == dispatch_table[count].op) &&
582 30 : (type == dispatch_table[count].type))
583 : {
584 10 : ret = dispatch_table[count].cmd(db, keyname, valuestr);
585 10 : break;
586 : }
587 : }
588 :
589 0 : done:
590 10 : poptFreeContext(pc);
591 10 : TALLOC_FREE(mem_ctx);
592 10 : return ret;
593 : }
|