CryptApplication.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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. char k = 0x5a;
  37. memcpy(buffer, &k, 1);
  38. fprintf(stderr, "\nTransfered key to server\n");
  39. }
  40. return 1;
  41. }
  42. };
  43. class App
  44. {
  45. public:
  46. App() :
  47. master(fb_get_master_interface()),
  48. statusWrapper(master->getStatus()), status(&statusWrapper),
  49. p(NULL), att(NULL), tra(NULL)
  50. { }
  51. ~App()
  52. {
  53. if (tra)
  54. {
  55. tra->rollback(status);
  56. if (status->getState() & IStatus::STATE_ERRORS)
  57. {
  58. print("rollback");
  59. tra->release();
  60. }
  61. }
  62. if (att)
  63. {
  64. att->detach(status);
  65. if (status->getState() & IStatus::STATE_ERRORS)
  66. {
  67. print("detach");
  68. att->release();
  69. }
  70. }
  71. if (p)
  72. {
  73. p->release();
  74. }
  75. status->dispose();
  76. }
  77. enum Action {NONE, ENC, DEC, EX_LCL, EX_RMT};
  78. // Switches/actions have the following meanings:
  79. // ENC(-e) - encrypt database
  80. // DEC(-d) - decrypt database
  81. // EX_LCL(-l) - execute some predefined select command (demonstrates that database can respond to select request)
  82. // EX_RMT(-r) - execute select using execute statement in remote datasource (demonstrates that dbcrypt key is
  83. // passed to target database when using execute statement)
  84. void execute(const char* dbName, const Action a)
  85. {
  86. status->init();
  87. p = master->getDispatcher();
  88. p->setDbCryptCallback(status, &key);
  89. if (status->getState() & IStatus::STATE_ERRORS)
  90. throw "setDbCryptCallback";
  91. char s[256];
  92. sprintf(s, "localhost:%s", dbName);
  93. att = p->attachDatabase(status, s, 0, NULL);
  94. if (status->getState() & IStatus::STATE_ERRORS)
  95. throw "attachDatabase";
  96. if (a != NONE)
  97. {
  98. tra = att->startTransaction(status, 0, NULL);
  99. if (status->getState() & IStatus::STATE_ERRORS)
  100. throw "startTransaction";
  101. }
  102. switch(a)
  103. {
  104. case ENC:
  105. att->execute(status, tra, 0,
  106. "ALTER DATABASE ENCRYPT WITH \"fbSampleDbCrypt\"", 3, NULL, NULL, NULL, NULL);
  107. if (status->getState() & IStatus::STATE_ERRORS)
  108. throw "execute";
  109. break;
  110. case DEC:
  111. att->execute(status, tra, 0, "ALTER DATABASE DECRYPT", 3, NULL, NULL, NULL, NULL);
  112. if (status->getState() & IStatus::STATE_ERRORS)
  113. throw "execute";
  114. break;
  115. case EX_LCL:
  116. case EX_RMT:
  117. {
  118. FB_MESSAGE(Output, CheckStatusWrapper,
  119. (FB_VARCHAR(31), logon)
  120. ) output(status, master);
  121. const char* sqlL = "select current_user from rdb$database";
  122. const char* sqlR = "execute block returns(logon varchar(31)) as begin "
  123. "execute statement 'select current_user from rdb$database' "
  124. "on external 'localhost:employee' as user 'test' password 'test' into :logon; "
  125. "suspend; end";
  126. const char* sql = a == EX_LCL ? sqlL : sqlR;
  127. curs = att->openCursor(status, tra, 0, sql, 3, NULL, NULL, output.getMetadata(), NULL, 0);
  128. if (status->getState() & IStatus::STATE_ERRORS)
  129. throw "openCursor";
  130. printf("\nExec SQL: %s\nReturns:\n", sql);
  131. while (curs->fetchNext(status, output.getData()) == IStatus::RESULT_OK)
  132. {
  133. unsigned l = output->logonNull ? 0 : output->logon.length;
  134. printf("%*.*s\n", l, l, output->logon.str);
  135. }
  136. printf("done.\n");
  137. if (status->getState() & IStatus::STATE_ERRORS)
  138. throw "fetchNext";
  139. curs->close(status);
  140. if (status->getState() & IStatus::STATE_ERRORS)
  141. throw "close";
  142. curs = NULL;
  143. break;
  144. }
  145. }
  146. if (tra)
  147. {
  148. tra->commit(status);
  149. if (status->getState() & IStatus::STATE_ERRORS)
  150. throw "commit";
  151. tra = NULL;
  152. }
  153. printf("\nProviding key for crypt plugin - press enter to continue ...");
  154. getchar();
  155. att->detach(status);
  156. if (status->getState() & IStatus::STATE_ERRORS)
  157. throw "detach";
  158. att = NULL;
  159. p->release();
  160. p = NULL;
  161. }
  162. void print(const char* where)
  163. {
  164. fprintf(stderr, "Error in %s: ", where);
  165. isc_print_status(status->getErrors());
  166. }
  167. private:
  168. IMaster* master;
  169. CheckStatusWrapper statusWrapper;
  170. CheckStatusWrapper* status;
  171. IProvider* p;
  172. IAttachment* att;
  173. ITransaction* tra;
  174. IResultSet* curs;
  175. CryptKey key;
  176. };
  177. int usage()
  178. {
  179. fprintf(stderr, "Usage: cryptAppSample [ -e | -d | -l | -r ] { db-name }\n");
  180. return 2;
  181. }
  182. int main(int ac, char** av)
  183. {
  184. App::Action act = App::NONE;
  185. if (ac < 2 || ac > 3)
  186. return usage();
  187. if (ac == 3)
  188. {
  189. if (av[1][0] != '-')
  190. return usage();
  191. switch(av[1][1])
  192. {
  193. case 'e':
  194. act = App::ENC;
  195. break;
  196. case 'd':
  197. act = App::DEC;
  198. break;
  199. case 'l':
  200. act = App::EX_LCL;
  201. break;
  202. case 'r':
  203. act = App::EX_RMT;
  204. break;
  205. default:
  206. return usage();
  207. }
  208. av++;
  209. }
  210. #ifdef WIN_NT
  211. _putenv_s("ISC_USER", "sysdba");
  212. _putenv_s("ISC_PASSWORD", "masterkey");
  213. #else
  214. setenv("ISC_USER", "sysdba", 0);
  215. setenv("ISC_PASSWORD", "masterkey", 0);
  216. #endif
  217. App app;
  218. try
  219. {
  220. app.execute(av[1], act);
  221. }
  222. catch (const char* where)
  223. {
  224. app.print(where);
  225. return 1;
  226. }
  227. return 0;
  228. }