1/* 2 Unix SMB/CIFS implementation. 3 Samba database functions 4 Copyright (C) Andrew Tridgell 1999-2000 5 Copyright (C) Paul `Rusty' Russell 2000 6 Copyright (C) Jeremy Allison 2000 7 Copyright (C) Andrew Esh 2001 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 2 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, write to the Free Software 21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22*/ 23 24#include <errno.h> 25#include <stdlib.h> 26#include <stdio.h> 27#include <fcntl.h> 28#include <unistd.h> 29#include <string.h> 30#include <fcntl.h> 31#include <time.h> 32#include <sys/mman.h> 33#include <sys/stat.h> 34#include <sys/time.h> 35#include <ctype.h> 36#include <signal.h> 37#include "tdb.h" 38 39/* a tdb tool for manipulating a tdb database */ 40 41#define FSTRING_LEN 256 42typedef char fstring[FSTRING_LEN]; 43 44typedef struct connections_key { 45 pid_t pid; 46 int cnum; 47 fstring name; 48} connections_key; 49 50typedef struct connections_data { 51 int magic; 52 pid_t pid; 53 int cnum; 54 uid_t uid; 55 gid_t gid; 56 char name[24]; 57 char addr[24]; 58 char machine[128]; 59 time_t start; 60} connections_data; 61 62static TDB_CONTEXT *tdb; 63 64static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state); 65 66static void print_asc(unsigned char *buf,int len) 67{ 68 int i; 69 70 /* We're probably printing ASCII strings so don't try to display 71 the trailing NULL character. */ 72 73 if (buf[len - 1] == 0) 74 len--; 75 76 for (i=0;i<len;i++) 77 printf("%c",isprint(buf[i])?buf[i]:'.'); 78} 79 80static void print_data(unsigned char *buf,int len) 81{ 82 int i=0; 83 if (len<=0) return; 84 printf("[%03X] ",i); 85 for (i=0;i<len;) { 86 printf("%02X ",(int)buf[i]); 87 i++; 88 if (i%8 == 0) printf(" "); 89 if (i%16 == 0) { 90 print_asc(&buf[i-16],8); printf(" "); 91 print_asc(&buf[i-8],8); printf("\n"); 92 if (i<len) printf("[%03X] ",i); 93 } 94 } 95 if (i%16) { 96 int n; 97 98 n = 16 - (i%16); 99 printf(" "); 100 if (n>8) printf(" "); 101 while (n--) printf(" "); 102 103 n = i%16; 104 if (n > 8) n = 8; 105 print_asc(&buf[i-(i%16)],n); printf(" "); 106 n = (i%16) - n; 107 if (n>0) print_asc(&buf[i-n],n); 108 printf("\n"); 109 } 110} 111 112static void help(void) 113{ 114 printf("\n" 115"tdbtool: \n" 116" create dbname : create a database\n" 117" open dbname : open an existing database\n" 118" erase : erase the database\n" 119" dump : dump the database as strings\n" 120" insert key data : insert a record\n" 121" move key file : move a record to a destination tdb\n" 122" store key data : store a record (replace)\n" 123" show key : show a record by key\n" 124" delete key : delete a record by key\n" 125" list : print the database hash table and freelist\n" 126" free : print the database freelist\n" 127" 1 | first : print the first record\n" 128" n | next : print the next record\n" 129" q | quit : terminate\n" 130" \\n : repeat 'next' command\n" 131"\n"); 132} 133 134static void terror(char *why) 135{ 136 printf("%s\n", why); 137} 138 139static char *get_token(int startover) 140{ 141 static char tmp[1024]; 142 static char *cont = NULL; 143 char *insert, *start; 144 char *k = strtok(NULL, " "); 145 146 if (!k) 147 return NULL; 148 149 if (startover) 150 start = tmp; 151 else 152 start = cont; 153 154 strcpy(start, k); 155 insert = start + strlen(start) - 1; 156 while (*insert == '\\') { 157 *insert++ = ' '; 158 k = strtok(NULL, " "); 159 if (!k) 160 break; 161 strcpy(insert, k); 162 insert = start + strlen(start) - 1; 163 } 164 165 /* Get ready for next call */ 166 cont = start + strlen(start) + 1; 167 return start; 168} 169 170static void create_tdb(void) 171{ 172 char *tok = get_token(1); 173 if (!tok) { 174 help(); 175 return; 176 } 177 if (tdb) tdb_close(tdb); 178 tdb = tdb_open(tok, 0, TDB_CLEAR_IF_FIRST, 179 O_RDWR | O_CREAT | O_TRUNC, 0600); 180 if (!tdb) { 181 printf("Could not create %s: %s\n", tok, strerror(errno)); 182 } 183} 184 185static void open_tdb(void) 186{ 187 char *tok = get_token(1); 188 if (!tok) { 189 help(); 190 return; 191 } 192 if (tdb) tdb_close(tdb); 193 tdb = tdb_open(tok, 0, 0, O_RDWR, 0600); 194 if (!tdb) { 195 printf("Could not open %s: %s\n", tok, strerror(errno)); 196 } 197} 198 199static void insert_tdb(void) 200{ 201 char *k = get_token(1); 202 char *d = get_token(0); 203 TDB_DATA key, dbuf; 204 205 if (!k || !d) { 206 help(); 207 return; 208 } 209 210 key.dptr = k; 211 key.dsize = strlen(k)+1; 212 dbuf.dptr = d; 213 dbuf.dsize = strlen(d)+1; 214 215 if (tdb_store(tdb, key, dbuf, TDB_INSERT) == -1) { 216 terror("insert failed"); 217 } 218} 219 220static void store_tdb(void) 221{ 222 char *k = get_token(1); 223 char *d = get_token(0); 224 TDB_DATA key, dbuf; 225 226 if (!k || !d) { 227 help(); 228 return; 229 } 230 231 key.dptr = k; 232 key.dsize = strlen(k)+1; 233 dbuf.dptr = d; 234 dbuf.dsize = strlen(d)+1; 235 236 printf("Storing key:\n"); 237 print_rec(tdb, key, dbuf, NULL); 238 239 if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) { 240 terror("store failed"); 241 } 242} 243 244static void show_tdb(void) 245{ 246 char *k = get_token(1); 247 TDB_DATA key, dbuf; 248 249 if (!k) { 250 help(); 251 return; 252 } 253 254 key.dptr = k; 255 key.dsize = strlen(k)+1; 256 257 dbuf = tdb_fetch(tdb, key); 258 if (!dbuf.dptr) { 259 /* maybe it is non-NULL terminated key? */ 260 key.dsize = strlen(k); 261 dbuf = tdb_fetch(tdb, key); 262 263 if ( !dbuf.dptr ) { 264 terror("fetch failed"); 265 return; 266 } 267 } 268 269 /* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */ 270 print_rec(tdb, key, dbuf, NULL); 271 272 free( dbuf.dptr ); 273 274 return; 275} 276 277static void delete_tdb(void) 278{ 279 char *k = get_token(1); 280 TDB_DATA key; 281 282 if (!k) { 283 help(); 284 return; 285 } 286 287 key.dptr = k; 288 key.dsize = strlen(k)+1; 289 290 if (tdb_delete(tdb, key) != 0) { 291 terror("delete failed"); 292 } 293} 294 295static void move_rec(void) 296{ 297 char *k = get_token(1); 298 char *file = get_token(0); 299 TDB_DATA key, dbuf; 300 TDB_CONTEXT *dst_tdb; 301 302 if (!k) { 303 help(); 304 return; 305 } 306 307 if ( !file ) { 308 terror("need destination tdb name"); 309 return; 310 } 311 312 key.dptr = k; 313 key.dsize = strlen(k)+1; 314 315 dbuf = tdb_fetch(tdb, key); 316 if (!dbuf.dptr) { 317 /* maybe it is non-NULL terminated key? */ 318 key.dsize = strlen(k); 319 dbuf = tdb_fetch(tdb, key); 320 321 if ( !dbuf.dptr ) { 322 terror("fetch failed"); 323 return; 324 } 325 } 326 327 print_rec(tdb, key, dbuf, NULL); 328 329 dst_tdb = tdb_open(file, 0, 0, O_RDWR, 0600); 330 if ( !dst_tdb ) { 331 terror("unable to open destination tdb"); 332 return; 333 } 334 335 if ( tdb_store( dst_tdb, key, dbuf, TDB_REPLACE ) == -1 ) { 336 terror("failed to move record"); 337 } 338 else 339 printf("record moved\n"); 340 341 tdb_close( dst_tdb ); 342 343 return; 344} 345 346#if 0 347static int print_conn_key(TDB_DATA key) 348{ 349 printf( "pid =%5d ", ((connections_key*)key.dptr)->pid); 350 printf( "cnum =%10d ", ((connections_key*)key.dptr)->cnum); 351 printf( "name =[%s]\n", ((connections_key*)key.dptr)->name); 352 return 0; 353} 354 355static int print_conn_data(TDB_DATA dbuf) 356{ 357 printf( "pid =%5d ", ((connections_data*)dbuf.dptr)->pid); 358 printf( "cnum =%10d ", ((connections_data*)dbuf.dptr)->cnum); 359 printf( "name =[%s]\n", ((connections_data*)dbuf.dptr)->name); 360 361 printf( "uid =%5d ", ((connections_data*)dbuf.dptr)->uid); 362 printf( "addr =[%s]\n", ((connections_data*)dbuf.dptr)->addr); 363 printf( "gid =%5d ", ((connections_data*)dbuf.dptr)->gid); 364 printf( "machine=[%s]\n", ((connections_data*)dbuf.dptr)->machine); 365 printf( "start = %s\n", ctime(&((connections_data*)dbuf.dptr)->start)); 366 return 0; 367} 368#endif 369 370static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state) 371{ 372#if 0 373 print_conn_key(key); 374 print_conn_data(dbuf); 375 return 0; 376#else 377 printf("\nkey %d bytes\n", key.dsize); 378 print_asc(key.dptr, key.dsize); 379 printf("\ndata %d bytes\n", dbuf.dsize); 380 print_data(dbuf.dptr, dbuf.dsize); 381 return 0; 382#endif 383} 384 385static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state) 386{ 387 print_asc(key.dptr, key.dsize); 388 printf("\n"); 389 return 0; 390} 391 392static int total_bytes; 393 394static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state) 395{ 396 total_bytes += dbuf.dsize; 397 return 0; 398} 399 400static void info_tdb(void) 401{ 402 int count; 403 total_bytes = 0; 404 if ((count = tdb_traverse(tdb, traverse_fn, NULL) == -1)) 405 printf("Error = %s\n", tdb_errorstr(tdb)); 406 else 407 printf("%d records totalling %d bytes\n", count, total_bytes); 408} 409 410static char *tdb_getline(char *prompt) 411{ 412 static char line[1024]; 413 char *p; 414 fputs(prompt, stdout); 415 line[0] = 0; 416 p = fgets(line, sizeof(line)-1, stdin); 417 if (p) p = strchr(p, '\n'); 418 if (p) *p = 0; 419 return p?line:NULL; 420} 421 422static int do_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, 423 void *state) 424{ 425 return tdb_delete(the_tdb, key); 426} 427 428static void first_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey) 429{ 430 TDB_DATA dbuf; 431 *pkey = tdb_firstkey(the_tdb); 432 433 dbuf = tdb_fetch(the_tdb, *pkey); 434 if (!dbuf.dptr) terror("fetch failed"); 435 else { 436 /* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */ 437 print_rec(the_tdb, *pkey, dbuf, NULL); 438 } 439} 440 441static void next_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey) 442{ 443 TDB_DATA dbuf; 444 *pkey = tdb_nextkey(the_tdb, *pkey); 445 446 dbuf = tdb_fetch(the_tdb, *pkey); 447 if (!dbuf.dptr) 448 terror("fetch failed"); 449 else 450 /* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */ 451 print_rec(the_tdb, *pkey, dbuf, NULL); 452} 453 454int main(int argc, char *argv[]) 455{ 456 int bIterate = 0; 457 char *line; 458 char *tok; 459 TDB_DATA iterate_kbuf; 460 461 if (argv[1]) { 462 static char tmp[1024]; 463 sprintf(tmp, "open %s", argv[1]); 464 tok=strtok(tmp," "); 465 open_tdb(); 466 } 467 468 while ((line = tdb_getline("tdb> "))) { 469 470 /* Shell command */ 471 472 if (line[0] == '!') { 473 system(line + 1); 474 continue; 475 } 476 477 if ((tok = strtok(line," "))==NULL) { 478 if (bIterate) 479 next_record(tdb, &iterate_kbuf); 480 continue; 481 } 482 if (strcmp(tok,"create") == 0) { 483 bIterate = 0; 484 create_tdb(); 485 continue; 486 } else if (strcmp(tok,"open") == 0) { 487 open_tdb(); 488 continue; 489 } else if ((strcmp(tok, "q") == 0) || 490 (strcmp(tok, "quit") == 0)) { 491 break; 492 } 493 494 /* all the rest require a open database */ 495 if (!tdb) { 496 bIterate = 0; 497 terror("database not open"); 498 help(); 499 continue; 500 } 501 502 if (strcmp(tok,"insert") == 0) { 503 bIterate = 0; 504 insert_tdb(); 505 } else if (strcmp(tok,"store") == 0) { 506 bIterate = 0; 507 store_tdb(); 508 } else if (strcmp(tok,"show") == 0) { 509 bIterate = 0; 510 show_tdb(); 511 } else if (strcmp(tok,"erase") == 0) { 512 bIterate = 0; 513 tdb_traverse(tdb, do_delete_fn, NULL); 514 } else if (strcmp(tok,"delete") == 0) { 515 bIterate = 0; 516 delete_tdb(); 517 } else if (strcmp(tok,"dump") == 0) { 518 bIterate = 0; 519 tdb_traverse(tdb, print_rec, NULL); 520 } else if (strcmp(tok,"move") == 0) { 521 bIterate = 0; 522 move_rec(); 523 } else if (strcmp(tok,"list") == 0) { 524 tdb_dump_all(tdb); 525 } else if (strcmp(tok, "free") == 0) { 526 tdb_printfreelist(tdb); 527 } else if (strcmp(tok,"info") == 0) { 528 info_tdb(); 529 } else if ( (strcmp(tok, "1") == 0) || 530 (strcmp(tok, "first") == 0)) { 531 bIterate = 1; 532 first_record(tdb, &iterate_kbuf); 533 } else if ((strcmp(tok, "n") == 0) || 534 (strcmp(tok, "next") == 0)) { 535 next_record(tdb, &iterate_kbuf); 536 } else if ((strcmp(tok, "keys") == 0)) { 537 bIterate = 0; 538 tdb_traverse(tdb, print_key, NULL); 539 } else { 540 help(); 541 } 542 } 543 544 if (tdb) tdb_close(tdb); 545 546 return 0; 547} 548