2
0

CryptApplication.cpp 6.1 KB

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