CryptApplication.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. * PROGRAM: Firebird samples.
  3. * MODULE: CryptApplication.cpp
  4. * DESCRIPTION: Sample of passing a key to crypt plugin
  5. *
  6. * The contents of this file are subject to the Initial
  7. * Developer's Public License Version 1.0 (the "License");
  8. * you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
  11. *
  12. * Software distributed under the License is distributed AS IS,
  13. * WITHOUT WARRANTY OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing rights
  15. * and limitations under the License.
  16. *
  17. * The Original Code was created by Alex Peshkov
  18. * for the Firebird Open Source RDBMS project.
  19. *
  20. * Copyright (c) 2012 Alex Peshkov <peshkoff at mail.ru>
  21. * and all contributors signed below.
  22. *
  23. * All Rights Reserved.
  24. * Contributor(s): ______________________________________.
  25. */
  26. #include "../interfaces/ifaceExamples.h"
  27. #include <firebird/Message.h>
  28. using namespace Firebird;
  29. class CryptKey : public ICryptKeyCallbackImpl<CryptKey, CheckStatusWrapper>
  30. {
  31. public:
  32. unsigned int callback(unsigned int, const void*, unsigned int length, void* buffer)
  33. {
  34. if (length > 0 && buffer)
  35. {
  36. memcpy(buffer, &k, 1);
  37. fprintf(stderr, "\nTransfered key to server\n");
  38. }
  39. return 1;
  40. }
  41. int getHashLength(Firebird::CheckStatusWrapper* status) override
  42. {
  43. return 1;
  44. }
  45. void getHashData(Firebird::CheckStatusWrapper* status, void* h) override
  46. {
  47. memcpy(h, &k, 1);
  48. }
  49. private:
  50. static const char k;
  51. };
  52. const char CryptKey::k = 0x5a;
  53. class App
  54. {
  55. public:
  56. App() :
  57. master(fb_get_master_interface()),
  58. statusWrapper(master->getStatus()), status(&statusWrapper),
  59. p(NULL), att(NULL), tra(NULL)
  60. { }
  61. ~App()
  62. {
  63. if (tra)
  64. {
  65. tra->rollback(status);
  66. if (status->getState() & IStatus::STATE_ERRORS)
  67. {
  68. print("rollback");
  69. tra->release();
  70. }
  71. }
  72. if (att)
  73. {
  74. att->detach(status);
  75. if (status->getState() & IStatus::STATE_ERRORS)
  76. {
  77. print("detach");
  78. att->release();
  79. }
  80. }
  81. if (p)
  82. {
  83. p->release();
  84. }
  85. status->dispose();
  86. }
  87. enum Action {NONE, ENC, DEC, EX_LCL, EX_RMT};
  88. // Switches/actions have the following meanings:
  89. // ENC(-e) - encrypt database
  90. // DEC(-d) - decrypt database
  91. // EX_LCL(-l) - execute some predefined select command (demonstrates that database can respond to select request)
  92. // EX_RMT(-r) - execute select using execute statement in remote datasource (demonstrates that dbcrypt key is
  93. // passed to target database when using execute statement)
  94. void execute(const char* dbName, const Action a)
  95. {
  96. status->init();
  97. p = master->getDispatcher();
  98. p->setDbCryptCallback(status, &key);
  99. if (status->getState() & IStatus::STATE_ERRORS)
  100. throw "setDbCryptCallback";
  101. char s[256];
  102. sprintf(s, "localhost:%s", dbName);
  103. att = p->attachDatabase(status, s, 0, NULL);
  104. if (status->getState() & IStatus::STATE_ERRORS)
  105. throw "attachDatabase";
  106. if (a != NONE)
  107. {
  108. tra = att->startTransaction(status, 0, NULL);
  109. if (status->getState() & IStatus::STATE_ERRORS)
  110. throw "startTransaction";
  111. }
  112. switch(a)
  113. {
  114. case ENC:
  115. att->execute(status, tra, 0,
  116. "ALTER DATABASE ENCRYPT WITH \"fbSampleDbCrypt\"", 3, NULL, NULL, NULL, NULL);
  117. if (status->getState() & IStatus::STATE_ERRORS)
  118. throw "execute";
  119. break;
  120. case DEC:
  121. att->execute(status, tra, 0, "ALTER DATABASE DECRYPT", 3, NULL, NULL, NULL, NULL);
  122. if (status->getState() & IStatus::STATE_ERRORS)
  123. throw "execute";
  124. break;
  125. case EX_LCL:
  126. case EX_RMT:
  127. {
  128. FB_MESSAGE(Output, CheckStatusWrapper,
  129. (FB_VARCHAR(31), logon)
  130. ) output(status, master);
  131. const char* sqlL = "select current_user from rdb$database";
  132. const char* sqlR = "execute block returns(logon varchar(31)) as begin "
  133. "execute statement 'select current_user from rdb$database' "
  134. "on external 'localhost:employee' as user 'test' password 'test' into :logon; "
  135. "suspend; end";
  136. const char* sql = a == EX_LCL ? sqlL : sqlR;
  137. curs = att->openCursor(status, tra, 0, sql, 3, NULL, NULL, output.getMetadata(), NULL, 0);
  138. if (status->getState() & IStatus::STATE_ERRORS)
  139. throw "openCursor";
  140. printf("\nExec SQL: %s\nReturns:\n", sql);
  141. while (curs->fetchNext(status, output.getData()) == IStatus::RESULT_OK)
  142. {
  143. unsigned l = output->logonNull ? 0 : output->logon.length;
  144. printf("%*.*s\n", l, l, output->logon.str);
  145. }
  146. printf("done.\n");
  147. if (status->getState() & IStatus::STATE_ERRORS)
  148. throw "fetchNext";
  149. curs->close(status);
  150. if (status->getState() & IStatus::STATE_ERRORS)
  151. throw "close";
  152. curs = NULL;
  153. break;
  154. }
  155. }
  156. if (tra)
  157. {
  158. tra->commit(status);
  159. if (status->getState() & IStatus::STATE_ERRORS)
  160. throw "commit";
  161. tra = NULL;
  162. }
  163. printf("\nProviding key for crypt plugin - press enter to continue ...");
  164. getchar();
  165. att->detach(status);
  166. if (status->getState() & IStatus::STATE_ERRORS)
  167. throw "detach";
  168. att = NULL;
  169. p->release();
  170. p = NULL;
  171. }
  172. void print(const char* where)
  173. {
  174. fprintf(stderr, "Error in %s: ", where);
  175. isc_print_status(status->getErrors());
  176. }
  177. private:
  178. IMaster* master;
  179. CheckStatusWrapper statusWrapper;
  180. CheckStatusWrapper* status;
  181. IProvider* p;
  182. IAttachment* att;
  183. ITransaction* tra;
  184. IResultSet* curs;
  185. CryptKey key;
  186. };
  187. int usage()
  188. {
  189. fprintf(stderr, "Usage: cryptAppSample [ -e | -d | -l | -r ] { db-name }\n");
  190. return 2;
  191. }
  192. int main(int ac, char** av)
  193. {
  194. App::Action act = App::NONE;
  195. if (ac < 2 || ac > 3)
  196. return usage();
  197. if (ac == 3)
  198. {
  199. if (av[1][0] != '-')
  200. return usage();
  201. switch(av[1][1])
  202. {
  203. case 'e':
  204. act = App::ENC;
  205. break;
  206. case 'd':
  207. act = App::DEC;
  208. break;
  209. case 'l':
  210. act = App::EX_LCL;
  211. break;
  212. case 'r':
  213. act = App::EX_RMT;
  214. break;
  215. default:
  216. return usage();
  217. }
  218. av++;
  219. }
  220. #ifdef WIN_NT
  221. _putenv_s("ISC_USER", "sysdba");
  222. _putenv_s("ISC_PASSWORD", "masterkey");
  223. #else
  224. setenv("ISC_USER", "sysdba", 0);
  225. setenv("ISC_PASSWORD", "masterkey", 0);
  226. #endif
  227. App app;
  228. try
  229. {
  230. app.execute(av[1], act);
  231. }
  232. catch (const char* where)
  233. {
  234. app.print(where);
  235. return 1;
  236. }
  237. return 0;
  238. }