tsigkey_python.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. // Copyright (C) 2010 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. // $Id$
  15. #include <new>
  16. #include <dns/tsigkey.h>
  17. using namespace isc::dns;
  18. using namespace isc::dns::rdata;
  19. //
  20. // Definition of the classes
  21. //
  22. // For each class, we need a struct, a helper functions (init, destroy,
  23. // and static wrappers around the methods we export), a list of methods,
  24. // and a type description
  25. namespace {
  26. //
  27. // TSIGKey
  28. //
  29. // The s_* Class simply covers one instantiation of the object
  30. class s_TSIGKey : public PyObject {
  31. public:
  32. s_TSIGKey() : tsigkey(NULL) {}
  33. TSIGKey* tsigkey;
  34. };
  35. //
  36. // We declare the functions here, the definitions are below
  37. // the type definition of the object, since both can use the other
  38. //
  39. // General creation and destruction
  40. int TSIGKey_init(s_TSIGKey* self, PyObject* args);
  41. void TSIGKey_destroy(s_TSIGKey* self);
  42. // These are the functions we export
  43. // This is a second version of toText, we need one where the argument
  44. // is a PyObject*, for the str() function in python.
  45. PyObject* TSIGKey_getKeyName(const s_TSIGKey* self);
  46. PyObject* TSIGKey_getAlgorithmName(const s_TSIGKey* self);
  47. PyObject* TSIGKey_getSecret(const s_TSIGKey* self);
  48. // This list contains the actual set of functions we have in
  49. // python. Each entry has
  50. // 1. Python method name
  51. // 2. Our static function here
  52. // 3. Argument type
  53. // 4. Documentation
  54. PyMethodDef TSIGKey_methods[] = {
  55. { "get_key_name",
  56. reinterpret_cast<PyCFunction>(TSIGKey_getKeyName), METH_NOARGS,
  57. "Return the key name." },
  58. { "get_algorithm_name",
  59. reinterpret_cast<PyCFunction>(TSIGKey_getAlgorithmName), METH_NOARGS,
  60. "Return the algorithm name." },
  61. { "get_secret",
  62. reinterpret_cast<PyCFunction>(TSIGKey_getSecret), METH_NOARGS,
  63. "Return the value of the TSIG secret." },
  64. { NULL, NULL, 0, NULL }
  65. };
  66. // This defines the complete type for reflection in python and
  67. // parsing of PyObject* to s_EDNS
  68. // Most of the functions are not actually implemented and NULL here.
  69. PyTypeObject tsigkey_type = {
  70. PyVarObject_HEAD_INIT(NULL, 0)
  71. "libdns_python.TSIGKey",
  72. sizeof(s_TSIGKey), // tp_basicsize
  73. 0, // tp_itemsize
  74. (destructor)TSIGKey_destroy, // tp_dealloc
  75. NULL, // tp_print
  76. NULL, // tp_getattr
  77. NULL, // tp_setattr
  78. NULL, // tp_reserved
  79. NULL, // tp_repr
  80. NULL, // tp_as_number
  81. NULL, // tp_as_sequence
  82. NULL, // tp_as_mapping
  83. NULL, // tp_hash
  84. NULL, // tp_call
  85. NULL, // tp_str
  86. NULL, // tp_getattro
  87. NULL, // tp_setattro
  88. NULL, // tp_as_buffer
  89. Py_TPFLAGS_DEFAULT, // tp_flags
  90. "The TSIGKey class holds a TSIG key along with some related attributes as "
  91. "defined in RFC2845.",
  92. NULL, // tp_traverse
  93. NULL, // tp_clear
  94. NULL, // tp_richcompare
  95. 0, // tp_weaklistoffset
  96. NULL, // tp_iter
  97. NULL, // tp_iternext
  98. TSIGKey_methods, // tp_methods
  99. NULL, // tp_members
  100. NULL, // tp_getset
  101. NULL, // tp_base
  102. NULL, // tp_dict
  103. NULL, // tp_descr_get
  104. NULL, // tp_descr_set
  105. 0, // tp_dictoffset
  106. (initproc)TSIGKey_init, // tp_init
  107. NULL, // tp_alloc
  108. PyType_GenericNew, // tp_new
  109. NULL, // tp_free
  110. NULL, // tp_is_gc
  111. NULL, // tp_bases
  112. NULL, // tp_mro
  113. NULL, // tp_cache
  114. NULL, // tp_subclasses
  115. NULL, // tp_weaklist
  116. NULL, // tp_del
  117. 0 // tp_version_tag
  118. };
  119. // A helper function to build a python "Name" object with error handling
  120. // encapsulated.
  121. s_Name*
  122. createNameObject(const Name& source) {
  123. s_Name* name = PyObject_New(s_Name, &name_type);
  124. if (name == NULL) {
  125. return (NULL);
  126. }
  127. name->name = new(nothrow) Name(source);
  128. if (name->name == NULL) {
  129. Py_DECREF(name);
  130. PyErr_SetString(po_IscException, "Allocating Name object failed");
  131. return (NULL);
  132. }
  133. return (name);
  134. }
  135. int
  136. TSIGKey_init(s_TSIGKey* self, PyObject* args) {
  137. const s_Name* key_name;
  138. const s_Name* algorithm_name;
  139. PyObject* bytes_obj;
  140. const char* secret;
  141. Py_ssize_t secret_len;
  142. if (PyArg_ParseTuple(args, "O!O!O", &name_type, &key_name,
  143. &name_type, &algorithm_name, &bytes_obj) &&
  144. PyObject_AsCharBuffer(bytes_obj, &secret, &secret_len) != -1) {
  145. try {
  146. self->tsigkey = new TSIGKey(*key_name->name,
  147. *algorithm_name->name,
  148. secret, secret_len);
  149. } catch (const isc::InvalidParameter& ex) {
  150. PyErr_SetString(po_InvalidParameter, ex.what());
  151. return (-1);
  152. } catch (...) {
  153. PyErr_SetString(po_IscException, "Unexpected exception");
  154. return (-1);
  155. }
  156. return (0);
  157. }
  158. PyErr_Clear();
  159. PyErr_SetString(PyExc_TypeError,
  160. "Invalid arguments to TSIGKey constructor");
  161. return (-1);
  162. }
  163. void
  164. TSIGKey_destroy(s_TSIGKey* const self) {
  165. delete self->tsigkey;
  166. self->tsigkey = NULL;
  167. Py_TYPE(self)->tp_free(self);
  168. }
  169. PyObject*
  170. TSIGKey_getKeyName(const s_TSIGKey* const self) {
  171. return (createNameObject(self->tsigkey->getKeyName()));
  172. }
  173. PyObject*
  174. TSIGKey_getAlgorithmName(const s_TSIGKey* const self) {
  175. return (createNameObject(self->tsigkey->getAlgorithmName()));
  176. }
  177. PyObject*
  178. TSIGKey_getSecret(const s_TSIGKey* const self) {
  179. return (Py_BuildValue("y#", self->tsigkey->getSecret(),
  180. self->tsigkey->getSecretLength()));
  181. }
  182. // Module Initialization, all statics are initialized here
  183. bool
  184. initModulePart_TSIGKey(PyObject* mod) {
  185. // We initialize the static description object with PyType_Ready(),
  186. // then add it to the module. This is not just a check! (leaving
  187. // this out results in segmentation faults)
  188. if (PyType_Ready(&tsigkey_type) < 0) {
  189. return (false);
  190. }
  191. Py_INCREF(&tsigkey_type);
  192. void* p = &tsigkey_type;
  193. if (PyModule_AddObject(mod, "TSIGKey", static_cast<PyObject*>(p)) != 0) {
  194. Py_DECREF(&tsigkey_type);
  195. return (false);
  196. }
  197. s_Name* name;
  198. if ((name = createNameObject(TSIGKey::HMACMD5_NAME())) == NULL) {
  199. goto cleanup;
  200. }
  201. addClassVariable(tsigkey_type, "HMACMD5_NAME", name);
  202. if ((name = createNameObject(TSIGKey::HMACSHA1_NAME())) == NULL) {
  203. goto cleanup;
  204. }
  205. addClassVariable(tsigkey_type, "HMACSHA1_NAME", name);
  206. if ((name = createNameObject(TSIGKey::HMACSHA256_NAME())) == NULL) {
  207. goto cleanup;
  208. }
  209. addClassVariable(tsigkey_type, "HMACSHA256_NAME", name);
  210. return (true);
  211. cleanup:
  212. Py_DECREF(&tsigkey_type);
  213. return (false);
  214. }
  215. //
  216. // End of TSIGKey
  217. //
  218. //
  219. // TSIGKeyRing
  220. //
  221. // The s_* Class simply covers one instantiation of the object
  222. // The s_* Class simply covers one instantiation of the object
  223. class s_TSIGKeyRing : public PyObject {
  224. public:
  225. s_TSIGKeyRing() : keyring(NULL) {}
  226. TSIGKeyRing* keyring;
  227. };
  228. //
  229. // We declare the functions here, the definitions are below
  230. // the type definition of the object, since both can use the other
  231. //
  232. int TSIGKeyRing_init(s_TSIGKeyRing* self, PyObject* args);
  233. void TSIGKeyRing_destroy(s_TSIGKeyRing* self);
  234. PyObject* TSIGKeyRing_size(const s_TSIGKeyRing* self);
  235. PyObject* TSIGKeyRing_add(const s_TSIGKeyRing* self, PyObject* args);
  236. PyObject* TSIGKeyRing_remove(const s_TSIGKeyRing* self, PyObject* args);
  237. PyObject* TSIGKeyRing_find(const s_TSIGKeyRing* self, PyObject* args);
  238. PyMethodDef TSIGKeyRing_methods[] = {
  239. { "size", reinterpret_cast<PyCFunction>(TSIGKeyRing_size), METH_NOARGS,
  240. "Return the number of keys stored in the TSIGKeyRing." },
  241. { "add", reinterpret_cast<PyCFunction>(TSIGKeyRing_add), METH_VARARGS,
  242. "Add a TSIGKey to the TSIGKeyRing." },
  243. { "remove", reinterpret_cast<PyCFunction>(TSIGKeyRing_remove),
  244. METH_VARARGS,
  245. "Remove a TSIGKey for the given name from the TSIGKeyRing." },
  246. { "find", reinterpret_cast<PyCFunction>(TSIGKeyRing_find), METH_VARARGS,
  247. "Find a TSIGKey for the given name in the TSIGKeyRing. "
  248. "It returns a tuple of (result_code, key)." },
  249. { NULL, NULL, 0, NULL }
  250. };
  251. PyTypeObject tsigkeyring_type = {
  252. PyVarObject_HEAD_INIT(NULL, 0)
  253. "libdns_python.TSIGKeyRing",
  254. sizeof(s_TSIGKeyRing), // tp_basicsize
  255. 0, // tp_itemsize
  256. (destructor)TSIGKeyRing_destroy, // tp_dealloc
  257. NULL, // tp_print
  258. NULL, // tp_getattr
  259. NULL, // tp_setattr
  260. NULL, // tp_reserved
  261. NULL, // tp_repr
  262. NULL, // tp_as_number
  263. NULL, // tp_as_sequence
  264. NULL, // tp_as_mapping
  265. NULL, // tp_hash
  266. NULL, // tp_call
  267. NULL, // tp_str
  268. NULL, // tp_getattro
  269. NULL, // tp_setattro
  270. NULL, // tp_as_buffer
  271. Py_TPFLAGS_DEFAULT, // tp_flags
  272. "A simple repository of a set of TSIGKey objects.",
  273. NULL, // tp_traverse
  274. NULL, // tp_clear
  275. NULL, // tp_richcompare
  276. 0, // tp_weaklistoffset
  277. NULL, // tp_iter
  278. NULL, // tp_iternext
  279. TSIGKeyRing_methods, // tp_methods
  280. NULL, // tp_members
  281. NULL, // tp_getset
  282. NULL, // tp_base
  283. NULL, // tp_dict
  284. NULL, // tp_descr_get
  285. NULL, // tp_descr_set
  286. 0, // tp_dictoffset
  287. (initproc)TSIGKeyRing_init, // tp_init
  288. NULL, // tp_alloc
  289. PyType_GenericNew, // tp_new
  290. NULL, // tp_free
  291. NULL, // tp_is_gc
  292. NULL, // tp_bases
  293. NULL, // tp_mro
  294. NULL, // tp_cache
  295. NULL, // tp_subclasses
  296. NULL, // tp_weaklist
  297. NULL, // tp_del
  298. 0 // tp_version_tag
  299. };
  300. int
  301. TSIGKeyRing_init(s_TSIGKeyRing* self, PyObject* args) {
  302. if (!PyArg_ParseTuple(args, "")) {
  303. PyErr_Clear();
  304. PyErr_SetString(PyExc_TypeError,
  305. "Invalid arguments to TSIGKeyRing constructor");
  306. return (-1);
  307. }
  308. self->keyring = new(nothrow) TSIGKeyRing();
  309. if (self->keyring == NULL) {
  310. PyErr_SetString(po_IscException, "Allocating TSIGKeyRing failed");
  311. return (-1);
  312. }
  313. return (0);
  314. }
  315. void
  316. TSIGKeyRing_destroy(s_TSIGKeyRing* self) {
  317. delete self->keyring;
  318. self->keyring = NULL;
  319. Py_TYPE(self)->tp_free(self);
  320. }
  321. PyObject*
  322. TSIGKeyRing_size(const s_TSIGKeyRing* const self) {
  323. return (Py_BuildValue("I", self->keyring->size()));
  324. }
  325. PyObject*
  326. TSIGKeyRing_add(const s_TSIGKeyRing* const self, PyObject* args) {
  327. s_TSIGKey* tsigkey;
  328. if (PyArg_ParseTuple(args, "O!", &tsigkey_type, &tsigkey)) {
  329. try {
  330. const TSIGKeyRing::Result result =
  331. self->keyring->add(*tsigkey->tsigkey);
  332. return (Py_BuildValue("I", result));
  333. } catch (...) {
  334. PyErr_SetString(po_IscException, "Unexpected exception");
  335. return (NULL);
  336. }
  337. }
  338. PyErr_Clear();
  339. PyErr_SetString(PyExc_TypeError, "Invalid arguments to TSIGKeyRing.add");
  340. return (NULL);
  341. }
  342. PyObject*
  343. TSIGKeyRing_remove(const s_TSIGKeyRing* self, PyObject* args) {
  344. s_Name* key_name;
  345. if (PyArg_ParseTuple(args, "O!", &name_type, &key_name)) {
  346. const TSIGKeyRing::Result result =
  347. self->keyring->remove(*key_name->name);
  348. return (Py_BuildValue("I", result));
  349. }
  350. PyErr_Clear();
  351. PyErr_SetString(PyExc_TypeError, "Invalid arguments to TSIGKeyRing.add");
  352. return (NULL);
  353. }
  354. PyObject*
  355. TSIGKeyRing_find(const s_TSIGKeyRing* self, PyObject* args) {
  356. s_Name* key_name;
  357. if (PyArg_ParseTuple(args, "O!", &name_type, &key_name)) {
  358. const TSIGKeyRing::FindResult result =
  359. self->keyring->find(*key_name->name);
  360. if (result.key != NULL) {
  361. s_TSIGKey* key = PyObject_New(s_TSIGKey, &tsigkey_type);
  362. if (key == NULL) {
  363. return (NULL);
  364. }
  365. key->tsigkey = new(nothrow) TSIGKey(*result.key);
  366. if (key->tsigkey == NULL) {
  367. Py_DECREF(key);
  368. PyErr_SetString(po_IscException,
  369. "Allocating TSIGKey object failed");
  370. return (NULL);
  371. }
  372. return (Py_BuildValue("IN", result.code, key));
  373. } else {
  374. return (Py_BuildValue("Is", result.code, NULL));
  375. }
  376. }
  377. return (NULL);
  378. }
  379. bool
  380. initModulePart_TSIGKeyRing(PyObject* mod) {
  381. if (PyType_Ready(&tsigkeyring_type) < 0) {
  382. return (false);
  383. }
  384. Py_INCREF(&tsigkeyring_type);
  385. void* p = &tsigkeyring_type;
  386. if (PyModule_AddObject(mod, "TSIGKeyRing",
  387. static_cast<PyObject*>(p)) != 0) {
  388. Py_DECREF(&tsigkeyring_type);
  389. return (false);
  390. }
  391. addClassVariable(tsigkeyring_type, "SUCCESS",
  392. Py_BuildValue("I", TSIGKeyRing::SUCCESS));
  393. addClassVariable(tsigkeyring_type, "EXIST",
  394. Py_BuildValue("I", TSIGKeyRing::EXIST));
  395. addClassVariable(tsigkeyring_type, "NOTFOUND",
  396. Py_BuildValue("I", TSIGKeyRing::NOTFOUND));
  397. return (true);
  398. }
  399. } // end of unnamed namespace