1 /*
2  * 'dbtool' is a simple but powerful  commandline interface to the
3  * GNU gdbm system (or, alternatively the Berkeley DB), useful for
4  * shellscripts which needs a database for data storage.
5  */
6 
7 /*
8  *
9  *  This file  is part of the DBTOOL program.
10  *
11  *  By  accessing  this software,  DBTOOL, you  are  duly informed
12  *  of and agree to be  bound  by the  conditions  described below
13  *  in this notice:
14  *
15  *  This software product,  DBTOOL,  is developed by T.v. Dein
16  *  and  copyrighted  (C)  2001-2015  by  T.v. Dein,  with all
17  *  rights reserved.
18  *
19  *  There  is no charge for DBTOOL software.  You can redistribute
20  *  it and/or modify it under the terms of the GNU  General Public
21  *  License, which is incorporated by reference herein.
22  *
23  *  DBTOOL is distributed WITHOUT ANY WARRANTY, IMPLIED OR EXPRESS,
24  *  OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE or that
25  *  the use of it will not infringe on any third party's intellec-
26  *  tual property rights.
27  *
28  *  You  should  have received a copy of the  GNU  General  Public
29  *  License  along with DBTOOL.  Copies can also be obtained from:
30  *
31  *    http://www.gnu.org/licenses/gpl.txt
32  *
33  *  or by writing to:
34  *
35  *  Free Software Foundation, Inc.
36  *  59 Temple Place, Suite 330
37  *  Boston, MA 02111-1307
38  *  USA
39  *
40  *  Or contact:
41  *
42  *   "T.v. Dein" <tlinden@cpan.org>
43  *
44  *
45  */
46 
47 
48 
49 
50 #include "dbtool.h"
51 #include "engine.h"
52 #include "platform.h"
53 /*
54  * Initialize the database and get a new Db instance pointer
55  */
init()56 void Engine::init() {
57   pkg = PACKAGE;
58   int mode;
59 #ifdef HAVE_BERKELEY
60   int err;
61 #endif
62   if(config.filename == "") {
63     cerr << pkg << ": no database file specified!" << endl;
64     exit(1);
65   }
66 #ifdef HAVE_BERKELEY
67   db = new Db(NULL,0);
68   db->set_error_stream(&cerr);
69   db->set_errpfx(pkg.c_str());
70   if(config.readonly == 1)
71     mode = DB_RDONLY;
72   else
73     mode = DB_CREATE;
74 #else
75   if(config.readonly == 1)
76     mode = GDBM_READER;
77   else
78     mode = GDBM_WRCREAT;
79 #endif
80 
81 
82   if(config.force == 1) {
83 #ifdef HAVE_BERKELEY
84     if ((err = db->open(NULL, config.filename.c_str(), NULL, DB_HASH, mode, FILEMODE)) != 0) {
85       cerr << "Failed to open " + config.filename << "(" << strerror(err) << ")" << endl;
86       exit(1);
87     }
88 #else
89 
90     db = gdbm_open(
91 		   (char *)config.filename.c_str(),
92 		   BLOCKSIZE,
93 		   mode,
94 		   FILEMODE,
95 		   0
96 		   );
97 #endif
98   }
99   else {
100 #ifdef HAVE_BERKELEY
101     if ((err = db->open(NULL, config.filename.c_str(), NULL, DB_HASH, mode, FILEMODE)) != 0) {
102       cerr << "Failed to open " + config.filename << "(" << strerror(err) << ")" << endl;
103       exit(1);
104     }
105 #else
106     db = gdbm_open(
107 		   (char *)config.filename.c_str(),
108 		   BLOCKSIZE,
109 		   mode,
110 		   FILEMODE,
111 		   0
112 		   );
113 #endif
114   }
115 #ifndef HAVE_BERKELEY
116   if(!db) {
117     cerr << pkg << ": " << gdbm_strerror(gdbm_errno) << endl;
118     exit(1);
119   }
120 #endif
121 
122   /*
123    * ok, at this point everything is ok, usage is correct,
124    * database is open, now check the passphrase, if encrypted
125    * database requested.
126    */
127   if(config.encrypted) {
128     if(config.phrase == "") {
129       config.phrase = readpass();
130     }
131     rijn.init(config.phrase); /* this might fail */
132     config.phrase = "                                                                       ";
133   }
134 }
135 
136 
137 /*
138  * dump out all data in db
139  */
dump()140 void Engine::dump() {
141   init();
142 #ifdef HAVE_BERKELEY
143   try {
144     Dbc *dbcp;
145     db->cursor(NULL, &dbcp, 0);
146     Dbt key;
147     Dbt data;
148     while (dbcp->get(&key, &data, DB_NEXT) == 0) {
149       /* iterate over every tuple and dump it out */
150       string K((char *)key.get_data(), key.get_size());
151       string V((char *)data.get_data(), data.get_size());
152       if(config.reverse == 1) {
153 	cout << decode(V) << config.separator << K << endl;
154       }
155       else {
156 	cout << K << config.separator << decode(V) << endl;
157       }
158     }
159     dbcp->close();
160   }
161   catch (DbException &dbe) {
162     cerr << pkg << ": " << dbe.what() << "\n";
163   }
164   db->close(0);
165 #else
166   datum key;
167   datum value;
168   key = gdbm_firstkey(db);
169   while ( key.dptr != NULL ) {
170     /* iterate over every tuple and dump it out */
171     value = gdbm_fetch(db, key);
172     string K(key.dptr, key.dsize);
173     string V(value.dptr, value.dsize);
174     if(config.reverse == 1) {
175       cout << decode(V) << config.separator << K << endl;
176       }
177     else {
178       cout << K << config.separator << decode(V) << endl;
179     }
180     key = gdbm_nextkey(db,key);
181   }
182   gdbm_close(db);
183 #endif
184 }
185 
186 
187 
188 
189 /*
190  * search for regexp given in config.key
191  */
regexp()192 void Engine::regexp() {
193   init();
194   int num;
195   pcre *p_pcre;
196   pcre_extra *p_pcre_extra;
197   char *err_str;
198   int sub_len = 9;
199   int *sub_vec;
200   int erroffset;
201   p_pcre_extra = NULL;
202   p_pcre = pcre_compile((char *)config.key.c_str(), 0,
203 			(const char **)(&err_str), &erroffset, NULL);
204 #ifdef HAVE_BERKELEY
205     Dbc *dbcp;
206     db->cursor(NULL, &dbcp, 0);
207     Dbt key;
208     Dbt data;
209     while (dbcp->get(&key, &data, DB_NEXT) == 0) {
210       string K((char *)key.get_data(), key.get_size());
211       string V((char *)data.get_data(), data.get_size());
212 #else
213     datum key;
214     datum value;
215     key = gdbm_firstkey(db);
216     while ( key.dptr != NULL ) {
217       value = gdbm_fetch(db, key);
218       string K(key.dptr, key.dsize);
219       string V(value.dptr, value.dsize);
220 #endif
221       sub_vec = new int(sub_len);
222       num = pcre_exec(p_pcre, p_pcre_extra, (char *)K.c_str(),
223 		      (int)K.length(), 0, 0, (int *)sub_vec, sub_len);
224       if(num == 1){
225 	if(config.reverse == 1) {
226 	  cout << decode(V);
227 	  if(config.with == 1) {
228 	    cout << config.separator << K;
229 	  }
230 	  cout << endl;
231 	}
232 	else {
233 	  if(config.with == 1) {
234 	    cout << K << config.separator;
235 	  }
236 	  cout << decode(V) << endl;
237 	}
238       }
239       K = "";
240       V = "";
241       delete(sub_vec);
242 #ifndef HAVE_BERKELEY
243       key = gdbm_nextkey(db,key);
244 #endif
245     }
246     pcre_free(p_pcre);
247 #ifdef HAVE_BERKELEY
248     dbcp->close();
249     db->close(0);
250 #else
251   gdbm_close(db);
252 #endif
253 }
254 
255 
256 
257 
258 
259 
260 /*
261  * Insert data into the db
262  */
263 void Engine::from_input() {
264   init();
265 #ifdef HAVE_BERKELEY
266   int err;
267 #else
268   int ret;
269 #endif
270 
271   FILE *stream;
272   stream = fdopen(0, "r");
273   char c;
274   string mode = "key";
275   string key = "";
276   string value = "";
277   string line = "";
278 
279   int num, match;
280   pcre *p_pcre;
281   pcre_extra *p_pcre_extra;
282   char *err_str;
283   int sub_len = 9;
284   int *sub_vec;
285   char *v1;
286   char *v2;
287   int erroffset;
288   p_pcre_extra = NULL;
289   p_pcre = pcre_compile((char *)config.token.c_str(), 0,
290 			(const char **)(&err_str), &erroffset, NULL);
291   while((c = fgetc(stream)) != EOF) {
292     if(c == '\n') {
293       // record end
294       mode = "key";
295       if(config.token != "") {
296 	v1 = new char[line.length()];
297 	v2 = new char[line.length()];
298 	sub_vec = new int[sub_len];
299 	num = pcre_exec(p_pcre, p_pcre_extra, (char *)line.c_str(),
300 			(int)line.length(), 0, 0, (int *)sub_vec, sub_len);
301 	if(num < 0)
302 	  cerr << "Token \"" << config.token << "\" did not match on \"" << line << "\"!\n";
303 	else if(num == 1)
304 	  cerr << "Token " << config.token << " did not produce sub strings!\n";
305 	else {
306 	  match = pcre_copy_substring((char *)line.c_str(), sub_vec, num, 1, v1, line.length());
307 	  match = pcre_copy_substring((char *)line.c_str(), sub_vec, num, 2, v2, line.length());
308 	  if(config.reverse) {
309 	    value = v1;
310 	    key   = v2;
311 	  }
312 	  else {
313 	    value = v2;
314 	    key   = v1;
315 	  }
316 	}
317 	delete(sub_vec);
318 	pcre_free((void *)v1);
319 	pcre_free((void *)v2);
320 	line = "";
321       }
322       value = encode(value);
323 #ifdef HAVE_BERKELEY
324       Dbt d_key((char *)key.c_str(), key.length());
325       Dbt d_value((char *)value.c_str(), value.length());
326 #else
327       datum d_key = {(char *)key.c_str(), static_cast<int>(key.length())};
328       datum d_value = {(char *)value.c_str(), static_cast<int>(value.length())};
329 #endif
330       if(config.force == 1) {
331 #ifdef HAVE_BERKELEY
332 	if((err = db->put(0, &d_key, &d_value, 0)) != 0) {
333 	  cerr << "Database error" << "(" << strerror(err) << ")" << endl;
334 	  exit(1);
335 	}
336 #else
337 	ret = gdbm_store(db, d_key, d_value, GDBM_REPLACE);
338 #endif
339       }
340       else {
341 #ifdef HAVE_BERKELEY
342 	if((err = db->put(NULL, &d_key, &d_value, DB_NOOVERWRITE)) != 0) {
343 	  if(err == DB_KEYEXIST) {
344 	    cerr << "Key " + config.key + " already exists" << "(" << strerror(err) << ")" << endl;
345 	    exit(1);
346 	  }
347 	  else {
348 	    cerr << "Database error" << "(" << strerror(err) << ")" << endl;
349 	    exit(1);
350 	  }
351 	}
352 #else
353 	ret = gdbm_store(db, d_key, d_value, GDBM_INSERT);
354 #endif
355       }
356 #ifndef HAVE_BERKELEY
357       if(ret != 0) {
358 	cerr << pkg << ": " << gdbm_strerror(gdbm_errno) << endl;
359 	exit(1);
360       }
361 #endif
362       key = "";
363       value = "";
364       continue;
365     }
366     else if(c == config.separator && mode != "value" && config.token == "") {
367       // key ready, the following stuff is the data!
368       mode = "value";
369       continue;
370     }
371     if(config.token != "") {
372       /* we have a split token */
373       line += char(c);
374     }
375     else {
376       if(mode == "key")
377 	key += char(c);
378       else
379 	value += char(c);
380     }
381   }
382   pcre_free(p_pcre);
383 #ifdef HAVE_BERKELEY
384   db->close(0);
385 #else
386   gdbm_close(db);
387 #endif
388 }
389 
390 
391 /*
392  * Insert data into the db
393  */
394 void Engine::insert() {
395   init();
396   string __value;
397   __value = encode(config.value);
398 #ifdef HAVE_BERKELEY
399   int err;
400   char *k;
401   char *v;
402   k = (char *)config.key.c_str();
403   v = (char *)__value.c_str();
404   Dbt key(k, strlen(k));
405   Dbt value(v, strlen(v));
406 #else
407   int ret;
408   datum key   = {(char *)config.key.c_str(), static_cast<int>(config.key.length())};
409   datum value = {(char *)__value.c_str(), static_cast<int>(__value.length())};
410 #endif
411 
412   if(config.force == 1) {
413 #ifdef HAVE_BERKELEY
414     if((err = db->put(0, &key, &value, 0)) != 0) {
415       cerr << "Database error" << "(" << strerror(err) << ")" << endl;
416       exit(1);
417     }
418 #else
419     ret = gdbm_store(db, key, value, GDBM_REPLACE);
420 #endif
421   }
422   else {
423 #ifdef HAVE_BERKELEY
424     if((err = db->put(NULL, &key, &value, DB_NOOVERWRITE)) != 0) {
425       if(err == DB_KEYEXIST) {
426 	cerr << "Key " + config.key + " already exists" << "(" << strerror(err) << ")" << endl;
427 	exit(1);
428       }
429       else {
430 	cerr << "Database error" << "(" << strerror(err) << ")" << endl;
431 	exit(1);
432       }
433     }
434 #else
435     ret = gdbm_store(db, key, value, GDBM_INSERT);
436 #endif
437   }
438 #ifdef HAVE_BERKELEY
439   db->close(0);
440 #else
441   if(ret != 0) {
442     cerr << pkg << ": " << gdbm_strerror(gdbm_errno) << endl;
443     exit(1);
444   }
445   gdbm_close(db);
446 #endif
447 }
448 
449 
450 
451 /*
452  * update a database
453  */
454 void Engine::update() {
455   init();
456   string __value;
457   __value = encode(config.value);
458 #ifdef HAVE_BERKELEY
459   int err;
460   char *k;
461   char *v;
462   k = (char *)config.key.c_str();
463   v = (char *)__value.c_str();
464   Dbt key(k, strlen(k));
465   Dbt value(v, strlen(v));
466 #else
467   int ret;
468   datum key   = {(char *)config.key.c_str(), static_cast<int>(config.key.length())};
469   datum value = {(char *)__value.c_str(), static_cast<int>(__value.length())};
470 #endif
471 
472   if(config.force == 1) {
473 #ifdef HAVE_BERKELEY
474     if((err = db->put(0, &key, &value, 0)) != 0) {
475       cerr << "Database error" << "(" << strerror(err) << ")" << endl;
476       exit(1);
477     }
478 #else
479     ret = gdbm_store(db, key, value, GDBM_REPLACE);
480 #endif
481   }
482   else {
483 #ifdef HAVE_BERKELEY
484     Dbt val;
485     err = db->get(0, &key, &val, 0);
486     if(err == 0) {
487       /* key exists, do the update */
488       if((err = db->put(0, &key, &value, 0)) != 0) {
489 	cerr << "Database error" << "(" << strerror(err) << ")" << endl;
490 	exit(1);
491       }
492     }
493     else if(err == DB_NOTFOUND) {
494       cerr << "Key " << config.key << " does not exist\n";
495       exit(1);
496     }
497     else {
498       cerr << "Database error" << "(" << strerror(err) << ")" << endl;
499       exit(1);
500     }
501 #else
502     ret = gdbm_exists(db, key);
503     if(ret) {
504       ret = gdbm_store(db, key, value, GDBM_REPLACE);
505     }
506     else {
507       cerr << "Key " << config.key << " does not exist\n";
508       exit(1);
509     }
510 #endif
511   }
512 #ifdef HAVE_BERKELEY
513   db->close(0);
514 #else
515   if(ret != 0) {
516     cerr << pkg << ": " << gdbm_strerror(gdbm_errno) << endl;
517     exit(1);
518   }
519   gdbm_close(db);
520 #endif
521 }
522 
523 
524 
525 /*
526  * remove an entry
527  */
528 void Engine::remove() {
529   init();
530   int ret;
531 #ifdef HAVE_BERKELEY
532   Dbt key((char *)config.key.c_str(), config.key.length() + 1);
533   if((ret = db->del(NULL, &key, 0)) != 0) {
534     cerr << "Database error" << "(" << strerror(ret) << ")" << endl;
535     exit(1);
536   }
537   db->close(0);
538 #else
539   datum key   = {(char *)config.key.c_str(), static_cast<int>(config.key.length())};
540   ret = gdbm_delete(db, key);
541   gdbm_close(db);
542 #endif
543 }
544 
545 
546 
547 /*
548  * search for specific data
549  */
550 void Engine::select() {
551   init();
552 #ifdef HAVE_BERKELEY
553   int err;
554   char *k;
555   k = (char *)config.key.c_str();
556   Dbt key(k, strlen(k));
557   Dbt value;
558   err = db->get(0, &key, &value, 0);
559   if(err == 0) {
560     string gotvalue((char *)value.get_data(), value.get_size());
561     if(config.reverse == 1) {
562       cout << decode(gotvalue);
563       if(config.with == 1) {
564 	cout << config.separator << config.key;
565       }
566       cout << endl;
567     }
568     else {
569       if(config.with == 1) {
570 	cout << config.key << config.separator;
571       }
572       cout << decode(gotvalue) << endl;
573     }
574   }
575   else {
576     cerr << "Database error" << "(" << strerror(err) << ")" << endl;
577     exit(1);
578   }
579   db->close(0);
580 #else
581   datum content;
582   datum key   = {(char *)config.key.c_str(), static_cast<int>(config.key.length())};
583   content = gdbm_fetch(db, key);
584   string V(content.dptr, content.dsize);
585   if(config.with == 1)
586     cout << config.key << config.separator;
587   cout << decode(V) << endl;
588   gdbm_close(db);
589 #endif
590 }
591 
592 string Engine::encode(const string& data) {
593   if(config.encrypted) {
594     return rijn.encrypt(data);
595   }
596   else
597     return data;
598 }
599 
600 string Engine::decode(const string& data) {
601   if(config.encrypted) {
602     return rijn.decrypt(data);
603   }
604   else
605     return data;
606 }
607 
608