1/*
2 * PROGRAM: Firebird samples.
3 * MODULE: CryptKeyHolder.cpp
4 * DESCRIPTION: Sample of how key holder may be written.
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
27#include <stdio.h>
28#include <string.h>
29
30#include "firebird.h"
31#include "firebird/Crypt.h"
32
33#include "../common/classes/fb_atomic.h"
34
35using namespace Firebird;
36
37namespace
38{
39
40IMaster* master = NULL;
41IPluginManager* pluginManager = NULL;
42
43class PluginModule : public IPluginModule
44{
45public:
46 PluginModule()
47 : flag(false)
48 { }
49
50 void registerMe()
51 {
52 pluginManager->registerModule(this);
53 flag = true;
54 }
55
56 ~PluginModule()
57 {
58 if (flag)
59 {
60 pluginManager->unregisterModule(this);
61 doClean();
62 }
63 }
64
65 int FB_CARG getVersion()
66 {
67 return FB_PLUGIN_MODULE_VERSION;
68 }
69
70 IPluginModule* FB_CARG getModule()
71 {
72 return this;
73 }
74
75 void FB_CARG doClean()
76 {
77 flag = false;
78 }
79
80private:
81 bool flag;
82};
83
84PluginModule module;
85
86class CryptKeyHolder : public IKeyHolderPlugin
87{
88public:
89 explicit CryptKeyHolder(IPluginConfig* cnf)
90 : callbackInterface(this), config(cnf), key(0), owner(NULL)
91 {
92 config->addRef();
93 }
94
95 ~CryptKeyHolder()
96 {
97 config->release();
98 }
99
100 // IKeyHolderPlugin implementation
101 virtual int FB_CARG keyCallback(IStatus* status, ICryptKeyCallback* callback);
102 virtual ICryptKeyCallback* FB_CARG keyHandle(IStatus* status, const char* keyName);
103
104 int FB_CARG release()
105 {
106 if (--refCounter == 0)
107 {
108 delete this;
109 return 0;
110 }
111 return 1;
112 }
113
114 void FB_CARG addRef()
115 {
116 ++refCounter;
117 }
118
119 int FB_CARG getVersion()
120 {
121 return FB_KEYHOLDER_PLUGIN_VERSION;
122 }
123
124 IPluginModule* FB_CARG getModule()
125 {
126 return &module;
127 }
128
129 void FB_CARG setOwner(Firebird::IRefCounted* o)
130 {
131 owner = o;
132 }
133
134 IRefCounted* FB_CARG getOwner()
135 {
136 return owner;
137 }
138
139 UCHAR getKey()
140 {
141 return key;
142 }
143
144private:
145 class CallbackInterface : public ICryptKeyCallback
146 {
147 public:
148 explicit CallbackInterface(CryptKeyHolder* p)
149 : parent(p)
150 { }
151
152 unsigned int FB_CARG callback(unsigned int, const void*, unsigned int length, void* buffer)
153 {
154 UCHAR k = parent->getKey();
155 if (!k)
156 {
157 return 0;
158 }
159
160 if (length > 0 && buffer)
161 {
162 memcpy(buffer, &k, 1);
163 }
164 return 1;
165 }
166
167 int FB_CARG getVersion()
168 {
169 return FB_CRYPT_CALLBACK_VERSION;
170 }
171
172 IPluginModule* FB_CARG getModule()
173 {
174 return &module;
175 }
176
177 private:
178 CryptKeyHolder* parent;
179 };
180
181 CallbackInterface callbackInterface;
182
183 IPluginConfig* config;
184 UCHAR key;
185
186 AtomicCounter refCounter;
187 IRefCounted* owner;
188
189 void noKeyError(IStatus* status);
190};
191
192void CryptKeyHolder::noKeyError(IStatus* status)
193{
194 ISC_STATUS_ARRAY vector;
195 vector[0] = isc_arg_gds;
196 vector[1] = isc_random;
197 vector[2] = isc_arg_string;
198 vector[3] = (ISC_STATUS) "Key not set";
199 vector[4] = isc_arg_end;
200 status->set(vector);
201}
202
203int FB_CARG CryptKeyHolder::keyCallback(IStatus* status, ICryptKeyCallback* callback)
204{
205 status->init();
206
207 if (key != 0)
208 {
209 return 1;
210 }
211
212 IConfig* def = config->getDefaultConfig();
213 IConfigEntry* confEntry = def->find("Auto");
214 def->release();
215
216 if (confEntry)
217 {
218 char v = *(confEntry->getValue());
219 confEntry->release();
220 if (v == '1' || v == 'y' || v == 'Y' || v == 't' || v == 'T')
221 {
222 key = 0x5a;
223 return 1;
224 }
225 }
226
227 if (callback && callback->callback(0, NULL, 1, &key) != 1)
228 {
229 key = 0;
230 return 0;
231 }
232
233 return 1;
234}
235
236ICryptKeyCallback* FB_CARG CryptKeyHolder::keyHandle(IStatus* status, const char* keyName)
237{
238 if (strcmp(keyName, "sample") != 0)
239 {
240 return NULL;
241 }
242
243 return &callbackInterface;
244}
245
246class Factory : public IPluginFactory
247{
248public:
249 int FB_CARG getVersion()
250 {
251 return FB_PLUGIN_FACTORY_VERSION;
252 }
253
254 IPluginModule* FB_CARG getModule()
255 {
256 return &module;
257 }
258
259 IPluginBase* FB_CARG createPlugin(IPluginConfig* factoryParameter)
260 {
261 CryptKeyHolder* p = new CryptKeyHolder(factoryParameter);
262 p->addRef();
263 return p;
264 }
265};
266
267Factory factory;
268
269} // anonymous namespace
270
271extern "C" void FB_PLUGIN_ENTRY_POINT(IMaster* m)
272{
273 master = m;
274 pluginManager = master->getPluginManager();
275
276 module.registerMe();
277 pluginManager->registerPluginFactory(PluginType::KeyHolder, "CryptKeyHolder_example",
278 &factory);
279}
280