Branch data Line data Source code
1 : : // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
2 : : //
3 : : // Permission to use, copy, modify, and/or distribute this software for any
4 : : // purpose with or without fee is hereby granted, provided that the above
5 : : // copyright notice and this permission notice appear in all copies.
6 : : //
7 : : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8 : : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 : : // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10 : : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 : : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12 : : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 : : // PERFORMANCE OF THIS SOFTWARE.
14 : :
15 : : #define PY_SSIZE_T_CLEAN // need for "y#" below
16 : : #include <Python.h>
17 : :
18 : : #include <string>
19 : : #include <stdexcept>
20 : :
21 : : #include <exceptions/exceptions.h>
22 : :
23 : : #include <util/python/pycppwrapper_util.h>
24 : :
25 : : #include <dns/tsig.h>
26 : :
27 : : #include "pydnspp_common.h"
28 : : #include "name_python.h"
29 : : #include "tsigkey_python.h"
30 : : #include "tsigerror_python.h"
31 : : #include "tsigrecord_python.h"
32 : : #include "tsig_python.h"
33 : :
34 : : using namespace std;
35 : : using namespace isc;
36 : : using namespace isc::util::python;
37 : : using namespace isc::dns;
38 : : using namespace isc::dns::python;
39 : :
40 : : // For each class, we need a struct, a helper functions (init, destroy,
41 : : // and static wrappers around the methods we export), a list of methods,
42 : : // and a type description
43 : :
44 : : namespace {
45 : : // The s_* Class simply covers one instantiation of the object
46 : : class s_TSIGContext : public PyObject {
47 : : public:
48 : : s_TSIGContext() : cppobj(NULL) {};
49 : : TSIGContext* cppobj;
50 : : };
51 : :
52 : : // Shortcut type which would be convenient for adding class variables safely.
53 : : typedef CPPPyObjectContainer<s_TSIGContext, TSIGContext> TSIGContextContainer;
54 : :
55 : : //
56 : : // We declare the functions here, the definitions are below
57 : : // the type definition of the object, since both can use the other
58 : : //
59 : :
60 : : // General creation and destruction
61 : : int TSIGContext_init(s_TSIGContext* self, PyObject* args);
62 : : void TSIGContext_destroy(s_TSIGContext* self);
63 : :
64 : : // Class specific methods
65 : : PyObject* TSIGContext_getState(s_TSIGContext* self);
66 : : PyObject* TSIGContext_getError(s_TSIGContext* self);
67 : : PyObject* TSIGContext_sign(s_TSIGContext* self, PyObject* args);
68 : : PyObject* TSIGContext_verify(s_TSIGContext* self, PyObject* args);
69 : :
70 : : // These are the functions we export
71 : : // For a minimal support, we don't need them.
72 : :
73 : : // This list contains the actual set of functions we have in
74 : : // python. Each entry has
75 : : // 1. Python method name
76 : : // 2. Our static function here
77 : : // 3. Argument type
78 : : // 4. Documentation
79 : : PyMethodDef TSIGContext_methods[] = {
80 : : { "get_state", reinterpret_cast<PyCFunction>(TSIGContext_getState),
81 : : METH_NOARGS,
82 : : "Return the current state of the context (mainly for tests)" },
83 : : { "get_error", reinterpret_cast<PyCFunction>(TSIGContext_getError),
84 : : METH_NOARGS,
85 : : "Return the TSIG error as a result of the latest verification" },
86 : : { "sign",
87 : : reinterpret_cast<PyCFunction>(TSIGContext_sign), METH_VARARGS,
88 : : "Sign a DNS message." },
89 : : { "verify",
90 : : reinterpret_cast<PyCFunction>(TSIGContext_verify), METH_VARARGS,
91 : : "Verify a DNS message." },
92 : : { NULL, NULL, 0, NULL }
93 : : };
94 : :
95 : : int
96 : 177 : TSIGContext_init(s_TSIGContext* self, PyObject* args) {
97 : : try {
98 : : // "From key" constructor
99 : : const PyObject* tsigkey_obj;
100 [ + - ][ + + ]: 177 : if (PyArg_ParseTuple(args, "O!", &tsigkey_type, &tsigkey_obj)) {
101 [ + - ][ + - ]: 154 : self->cppobj = new TSIGContext(PyTSIGKey_ToTSIGKey(tsigkey_obj));
[ + - ]
102 : 154 : return (0);
103 : : }
104 : :
105 : : // "From key param + keyring" constructor
106 [ + - ]: 23 : PyErr_Clear();
107 : : const PyObject* keyname_obj;
108 : : const PyObject* algname_obj;
109 : : const PyObject* keyring_obj;
110 [ + - ]: 23 : if (PyArg_ParseTuple(args, "O!O!O!", &name_type, &keyname_obj,
111 : : &name_type, &algname_obj, &tsigkeyring_type,
112 [ + - ]: 23 : &keyring_obj)) {
113 : 23 : self->cppobj = new TSIGContext(PyName_ToName(keyname_obj),
114 : 23 : PyName_ToName(algname_obj),
115 [ + - ][ + - ]: 23 : PyTSIGKeyRing_ToTSIGKeyRing(keyring_obj));
[ + - ][ + - ]
[ + - ]
116 : 23 : return (0);
117 : : }
118 : 0 : } catch (const exception& ex) {
119 : : const string ex_what = "Failed to construct TSIGContext object: " +
120 [ # # ][ # # ]: 0 : string(ex.what());
121 [ # # ]: 0 : PyErr_SetString(po_IscException, ex_what.c_str());
122 : : return (-1);
123 [ # # ]: 0 : } catch (...) {
124 : : PyErr_SetString(po_IscException,
125 [ # # ]: 0 : "Unexpected exception in constructing TSIGContext");
126 : : return (-1);
127 : : }
128 : :
129 : : PyErr_SetString(PyExc_TypeError,
130 : 0 : "Invalid arguments to TSIGContext constructor");
131 : :
132 : 177 : return (-1);
133 : : }
134 : :
135 : : void
136 : 177 : TSIGContext_destroy(s_TSIGContext* const self) {
137 [ + - ]: 177 : delete self->cppobj;
138 : 177 : self->cppobj = NULL;
139 : 177 : Py_TYPE(self)->tp_free(self);
140 : 177 : }
141 : :
142 : : PyObject*
143 : 53 : TSIGContext_getState(s_TSIGContext* self) {
144 : 53 : return (Py_BuildValue("I", self->cppobj->getState()));
145 : : }
146 : :
147 : : PyObject*
148 : 29 : TSIGContext_getError(s_TSIGContext* self) {
149 : : try {
150 : : PyObjectContainer container(createTSIGErrorObject(
151 [ + - ][ + - ]: 29 : self->cppobj->getError()));
[ + - ]
152 [ + - ]: 29 : return (Py_BuildValue("O", container.get()));
153 : 0 : } catch (const exception& ex) {
154 : : const string ex_what =
155 : : "Unexpectedly failed to get TSIGContext error: " +
156 [ # # ][ # # ]: 0 : string(ex.what());
157 [ # # ]: 0 : PyErr_SetString(po_IscException, ex_what.c_str());
158 [ # # ]: 0 : } catch (...) {
159 : : PyErr_SetString(po_IscException,
160 [ # # ]: 0 : "Unexpected exception in TSIGContext.get_error");
161 : : }
162 : : return (NULL);
163 : : }
164 : :
165 : : PyObject*
166 : 24 : TSIGContext_sign(s_TSIGContext* self, PyObject* args) {
167 : 24 : long qid = 0;
168 : : const char* mac;
169 : : Py_ssize_t mac_size;
170 : :
171 [ + + ]: 24 : if (PyArg_ParseTuple(args, "ly#", &qid, &mac, &mac_size)) {
172 [ - + ]: 23 : if (qid < 0 || qid > 0xffff) {
173 : : PyErr_SetString(PyExc_ValueError,
174 : 0 : "TSIGContext.sign: QID out of range");
175 : 0 : return (NULL);
176 : : }
177 : :
178 : : try {
179 [ + + ][ + - ]: 45 : ConstTSIGRecordPtr record = self->cppobj->sign(qid, mac, mac_size);
180 [ + - ]: 22 : return (createTSIGRecordObject(*record));
181 : 2 : } catch (const TSIGContextError& ex) {
182 [ - + ]: 1 : PyErr_SetString(po_TSIGContextError, ex.what());
183 : 0 : } catch (const exception& ex) {
184 : : const string ex_what = "Unexpected failure in TSIG sign: " +
185 [ # # ][ # # ]: 0 : string(ex.what());
186 [ # # ]: 0 : PyErr_SetString(po_IscException, ex_what.c_str());
187 [ + - - ]: 1 : } catch (...) {
188 : : PyErr_SetString(PyExc_SystemError,
189 [ # # ]: 0 : "Unexpected failure in TSIG sign");
190 : : }
191 : : } else {
192 : : PyErr_SetString(PyExc_TypeError,
193 : 24 : "Invalid arguments to TSIGContext.sign");
194 : : }
195 : :
196 : : return (NULL);
197 : : }
198 : :
199 : : PyObject*
200 : 71 : TSIGContext_verify(s_TSIGContext* self, PyObject* args) {
201 : : const char* data;
202 : : Py_ssize_t data_len;
203 : : PyObject* py_record;
204 : : PyObject* py_maybe_none;
205 : : const TSIGRecord* record;
206 : :
207 [ + + ]: 71 : if (PyArg_ParseTuple(args, "O!y#", &tsigrecord_type, &py_record,
208 : 71 : &data, &data_len)) {
209 : 51 : record = &PyTSIGRecord_ToTSIGRecord(py_record);
210 [ - + ]: 20 : } else if (PyArg_ParseTuple(args, "Oy#", &py_maybe_none, &data,
211 : 20 : &data_len)) {
212 : : record = NULL;
213 : : } else {
214 : : PyErr_SetString(PyExc_TypeError,
215 : 0 : "Invalid arguments to TSIGContext.verify");
216 : 0 : return (NULL);
217 : : }
218 : 71 : PyErr_Clear();
219 : :
220 : : try {
221 [ + + ]: 71 : const TSIGError error = self->cppobj->verify(record, data, data_len);
222 [ + - ]: 71 : return (createTSIGErrorObject(error));
223 : 2 : } catch (const TSIGContextError& ex) {
224 [ - + ]: 1 : PyErr_SetString(po_TSIGContextError, ex.what());
225 : 2 : } catch (const InvalidParameter& ex) {
226 [ - + ]: 1 : PyErr_SetString(po_InvalidParameter, ex.what());
227 : 0 : } catch (const exception& ex) {
228 : : const string ex_what = "Unexpected failure in TSIG verify: " +
229 [ # # ][ # # ]: 0 : string(ex.what());
230 [ # # ]: 0 : PyErr_SetString(po_IscException, ex_what.c_str());
231 [ + + - - ]: 2 : } catch (...) {
232 [ # # ]: 0 : PyErr_SetString(PyExc_SystemError, "Unexpected failure in TSIG verify");
233 : : }
234 : :
235 : : return (NULL);
236 : : }
237 : : } // end of unnamed namespace
238 : :
239 : : namespace isc {
240 : : namespace dns {
241 : : namespace python {
242 : : // Definition of class specific exception(s)
243 : : PyObject* po_TSIGContextError;
244 : :
245 : : // This defines the complete type for reflection in python and
246 : : // parsing of PyObject* to s_TSIGContext
247 : : // Most of the functions are not actually implemented and NULL here.
248 : : PyTypeObject tsigcontext_type = {
249 : : PyVarObject_HEAD_INIT(NULL, 0)
250 : : "pydnspp.TSIGContext",
251 : : sizeof(s_TSIGContext), // tp_basicsize
252 : : 0, // tp_itemsize
253 : : reinterpret_cast<destructor>(TSIGContext_destroy), // tp_dealloc
254 : : NULL, // tp_print
255 : : NULL, // tp_getattr
256 : : NULL, // tp_setattr
257 : : NULL, // tp_reserved
258 : : NULL, // tp_repr
259 : : NULL, // tp_as_number
260 : : NULL, // tp_as_sequence
261 : : NULL, // tp_as_mapping
262 : : NULL, // tp_hash
263 : : NULL, // tp_call
264 : : NULL, // tp_str
265 : : NULL, // tp_getattro
266 : : NULL, // tp_setattro
267 : : NULL, // tp_as_buffer
268 : :
269 : : // We allow the python version of TSIGContext to act as a base class.
270 : : // From pure design point of view, this is wrong because it's not intended
271 : : // to be inherited. However, cryptographic operations are generally
272 : : // difficult to test, so it would be very advantageous if we can define
273 : : // a mock context class.
274 : : Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, // tp_flags
275 : :
276 : : "The TSIGContext class objects is...(COMPLETE THIS)",
277 : : NULL, // tp_traverse
278 : : NULL, // tp_clear
279 : : NULL, // tp_richcompare
280 : : 0, // tp_weaklistoffset
281 : : NULL, // tp_iter
282 : : NULL, // tp_iternext
283 : : TSIGContext_methods, // tp_methods
284 : : NULL, // tp_members
285 : : NULL, // tp_getset
286 : : NULL, // tp_base
287 : : NULL, // tp_dict
288 : : NULL, // tp_descr_get
289 : : NULL, // tp_descr_set
290 : : 0, // tp_dictoffset
291 : : reinterpret_cast<initproc>(TSIGContext_init), // tp_init
292 : : NULL, // tp_alloc
293 : : PyType_GenericNew, // tp_new
294 : : NULL, // tp_free
295 : : NULL, // tp_is_gc
296 : : NULL, // tp_bases
297 : : NULL, // tp_mro
298 : : NULL, // tp_cache
299 : : NULL, // tp_subclasses
300 : : NULL, // tp_weaklist
301 : : NULL, // tp_del
302 : : 0 // tp_version_tag
303 : : };
304 : :
305 : : bool
306 : 0 : PyTSIGContext_Check(PyObject* obj) {
307 [ # # ]: 0 : if (obj == NULL) {
308 [ # # ][ # # ]: 0 : isc_throw(PyCPPWrapperException, "obj argument NULL in typecheck");
309 : : }
310 [ # # ][ # # ]: 0 : return (PyObject_TypeCheck(obj, &tsigcontext_type));
311 : : }
312 : :
313 : : TSIGContext&
314 : 143 : PyTSIGContext_ToTSIGContext(PyObject* tsigcontext_obj) {
315 [ - + ]: 143 : if (tsigcontext_obj == NULL) {
316 [ # # ][ # # ]: 0 : isc_throw(PyCPPWrapperException,
317 : : "obj argument NULL in TSIGContext PyObject conversion");
318 : : }
319 : 143 : s_TSIGContext* tsigcontext = static_cast<s_TSIGContext*>(tsigcontext_obj);
320 : 143 : return (*tsigcontext->cppobj);
321 : : }
322 : :
323 : : } // namespace python
324 : : } // namespace dns
325 : 123 : } // namespace isc
|