2 * Python bindings to libcryptsetup
4 * Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved.
5 * Written by Martin Sivak
7 * This file is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This file is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this file; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include <structmember.h>
26 #include "libcryptsetup.h"
31 /* Type-specific fields go here. */
32 struct crypt_device *device;
36 PyObject *yesDialogCB;
37 PyObject *cmdLineLogCB;
38 PyObject *passwordDialogCB;
41 static int yesDialog(const char *msg, void *this)
43 CryptSetupObject *self = this;
44 PyObject *result, *arglist;
47 if (self->yesDialogCB){
48 arglist = Py_BuildValue("(s)", msg);
52 result = PyEval_CallObject(self->yesDialogCB, arglist);
58 if (!PyArg_Parse(result, "i", &r))
68 static int passwordDialog(const char *msg, char *buf, size_t length, void *this)
70 CryptSetupObject *self = this;
71 PyObject *result, *arglist;
75 if(self->passwordDialogCB){
76 arglist = Py_BuildValue("(s)", msg);
80 result = PyEval_CallObject(self->passwordDialogCB, arglist);
86 if (!PyArg_Parse(result, "z", &res)) {
91 strncpy(buf, res, length - 1);
103 static void cmdLineLog(int cls, const char *msg, void *this)
105 CryptSetupObject *self = this;
106 PyObject *result, *arglist;
108 if(self->cmdLineLogCB) {
109 arglist = Py_BuildValue("(is)", cls, msg);
113 result = PyEval_CallObject(self->cmdLineLogCB, arglist);
119 static void CryptSetup_dealloc(CryptSetupObject* self)
121 /* free the callbacks */
122 Py_XDECREF(self->yesDialogCB);
123 Py_XDECREF(self->cmdLineLogCB);
124 Py_XDECREF(self->passwordDialogCB);
126 free(self->activated_as);
128 crypt_free(self->device);
131 self->ob_type->tp_free((PyObject*)self);
134 static PyObject *CryptSetup_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
136 CryptSetupObject *self = (CryptSetupObject *)type->tp_alloc(type, 0);
139 self->yesDialogCB = NULL;
140 self->passwordDialogCB = NULL;
141 self->cmdLineLogCB = NULL;
142 self->activated_as = NULL;
145 return (PyObject *)self;
148 static PyObject *PyObjectResult(int is)
150 PyObject *result = Py_BuildValue("i", is);
153 PyErr_SetString(PyExc_RuntimeError, "Error during constructing values for return value");
158 #define CryptSetup_HELP "CryptSetup object\n\n\
159 constructor takes one to five arguments:\n\
160 __init__(device, name, yesDialog, passwordDialog, logFunc)\n\n\
161 yesDialog - python function with func(text) signature, \n\
162 which asks the user question text and returns 1\n\
163 of the answer was positive or 0 if not\n\
164 logFunc - python function with func(level, text) signature to log stuff somewhere"
166 static int CryptSetup_init(CryptSetupObject* self, PyObject *args, PyObject *kwds)
168 static char *kwlist[] = {"device", "name", "yesDialog", "passwordDialog", "logFunc", NULL};
169 PyObject *yesDialogCB = NULL,
170 *passwordDialogCB = NULL,
171 *cmdLineLogCB = NULL,
173 char *device = NULL, *deviceName = NULL;
176 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzOOO", kwlist, &device, &deviceName,
177 &yesDialogCB, &passwordDialogCB, &cmdLineLogCB))
181 if (crypt_init(&(self->device), device)) {
182 PyErr_SetString(PyExc_IOError, "Device cannot be opened");
185 /* Try to load header form device */
186 r = crypt_load(self->device, NULL, NULL);
187 if (r && r != -EINVAL) {
188 PyErr_SetString(PyExc_RuntimeError, "Cannot initialize device context");
191 } else if (deviceName) {
192 if (crypt_init_by_name(&(self->device), deviceName)) {
193 PyErr_SetString(PyExc_IOError, "Device cannot be opened");
196 /* Context is initialized automatically from active device */
198 PyErr_SetString(PyExc_RuntimeError, "Either device file or luks name has to be specified");
203 self->activated_as = strdup(deviceName);
206 tmp = self->yesDialogCB;
207 Py_INCREF(yesDialogCB);
208 self->yesDialogCB = yesDialogCB;
210 crypt_set_confirm_callback(self->device, yesDialog, self);
213 if (passwordDialogCB) {
214 tmp = self->passwordDialogCB;
215 Py_INCREF(passwordDialogCB);
216 self->passwordDialogCB = passwordDialogCB;
218 crypt_set_password_callback(self->device, passwordDialog, self);
222 tmp = self->cmdLineLogCB;
223 Py_INCREF(cmdLineLogCB);
224 self->cmdLineLogCB = cmdLineLogCB;
226 crypt_set_log_callback(self->device, cmdLineLog, self);
232 #define CryptSetup_activate_HELP "Activate LUKS device\n\n\
235 static PyObject *CryptSetup_activate(CryptSetupObject* self, PyObject *args, PyObject *kwds)
237 static char *kwlist[] = {"name", "passphrase", NULL};
238 char *name = NULL, *passphrase = NULL;
241 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|s", kwlist, &name, &passphrase))
244 // FIXME: allow keyfile and \0 in passphrase
245 is = crypt_activate_by_passphrase(self->device, name, CRYPT_ANY_SLOT,
246 passphrase, passphrase ? strlen(passphrase) : 0, 0);
249 free(self->activated_as);
250 self->activated_as = strdup(name);
253 return PyObjectResult(is);
256 #define CryptSetup_deactivate_HELP "Dectivate LUKS device\n\n\
259 static PyObject *CryptSetup_deactivate(CryptSetupObject* self, PyObject *args, PyObject *kwds)
261 int is = crypt_deactivate(self->device, self->activated_as);
264 free(self->activated_as);
265 self->activated_as = NULL;
268 return PyObjectResult(is);
271 #define CryptSetup_askyes_HELP "Asks a question using the configured dialog CB\n\n\
274 static PyObject *CryptSetup_askyes(CryptSetupObject* self, PyObject *args, PyObject *kwds)
276 static char *kwlist[] = {"message", NULL};
277 PyObject *message = NULL, *result, *arglist;
279 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &message))
284 arglist = Py_BuildValue("(O)", message);
286 PyErr_SetString(PyExc_RuntimeError, "Error during constructing values for internal call");
290 result = PyEval_CallObject(self->yesDialogCB, arglist);
297 #define CryptSetup_log_HELP "Logs a string using the configured log CB\n\n\
298 log(int level, message)"
300 static PyObject *CryptSetup_log(CryptSetupObject* self, PyObject *args, PyObject *kwds)
302 static char *kwlist[] = {"priority", "message", NULL};
303 PyObject *message = NULL, *priority = NULL, *result, *arglist;
305 if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &message, &priority))
311 arglist = Py_BuildValue("(OO)", message, priority);
313 PyErr_SetString(PyExc_RuntimeError, "Error during constructing values for internal call");
317 result = PyEval_CallObject(self->cmdLineLogCB, arglist);
325 #define CryptSetup_luksUUID_HELP "Get UUID of the LUKS device\n\n\
328 static PyObject *CryptSetup_luksUUID(CryptSetupObject* self, PyObject *args, PyObject *kwds)
332 result = Py_BuildValue("s", crypt_get_uuid(self->device));
334 PyErr_SetString(PyExc_RuntimeError, "Error during constructing values for return value");
339 #define CryptSetup_isLuks_HELP "Is the device LUKS?\n\n\
342 static PyObject *CryptSetup_isLuks(CryptSetupObject* self, PyObject *args, PyObject *kwds)
344 return PyObjectResult(crypt_load(self->device, CRYPT_LUKS1, NULL));
347 #define CryptSetup_Info_HELP "Returns dictionary with info about opened device\nKeys:\n\
348 dir\n name\n uuid\n cipher\n cipher_mode\n keysize\n device\n\
349 offset\n size\n skip\n mode\n"
351 static PyObject *CryptSetup_Info(CryptSetupObject* self, PyObject *args, PyObject *kwds)
355 result = Py_BuildValue("{s:s,s:s,s:z,s:s,s:s,s:s,s:i,s:K}",
356 "dir", crypt_get_dir(),
357 "device", crypt_get_device_name(self->device),
358 "name", self->activated_as,
359 "uuid", crypt_get_uuid(self->device),
360 "cipher", crypt_get_cipher(self->device),
361 "cipher_mode", crypt_get_cipher_mode(self->device),
362 "keysize", crypt_get_volume_key_size(self->device) * 8,
364 //"mode", (co.flags & CRYPT_FLAG_READONLY) ? "readonly" : "read/write",
365 "offset", crypt_get_data_offset(self->device)
369 PyErr_SetString(PyExc_RuntimeError, "Error during constructing values for return value");
374 #define CryptSetup_luksFormat_HELP "Format device to enable LUKS\n\n\
375 luksFormat(cipher = 'aes', cipherMode = 'cbc-essiv:sha256', keysize = 256)\n\n\
376 cipher - cipher specification, e.g. aes, serpent\n\
377 cipherMode - cipher mode specification, e.g. cbc-essiv:sha256, xts-plain64\n\
378 keysize - key size in bits"
380 static PyObject *CryptSetup_luksFormat(CryptSetupObject* self, PyObject *args, PyObject *kwds)
382 static char *kwlist[] = {"cipher", "cipherMode", "keysize", NULL};
383 char *cipher_mode = NULL, *cipher = NULL;
385 PyObject *keysize_object = NULL;
387 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzO", kwlist,
388 &cipher, &cipher_mode, &keysize_object))
391 if (!keysize_object || keysize_object == Py_None) {
392 /* use default value */
393 } else if (!PyInt_Check(keysize_object)) {
394 PyErr_SetString(PyExc_TypeError, "keysize must be an integer");
396 } else if (PyInt_AsLong(keysize_object) % 8) {
397 PyErr_SetString(PyExc_TypeError, "keysize must have integer value dividable by 8");
399 } else if (PyInt_AsLong(keysize_object) <= 0) {
400 PyErr_SetString(PyExc_TypeError, "keysize must be positive number bigger than 0");
403 keysize = PyInt_AsLong(keysize_object);
405 // FIXME use #defined defaults
406 return PyObjectResult(crypt_format(self->device, CRYPT_LUKS1,
407 cipher ?: "aes", cipher_mode ?: "cbc-essiv:sha256",
408 NULL, NULL, keysize / 8, NULL));
411 #define CryptSetup_addKeyByPassphrase_HELP "Initialize keyslot using passphrase\n\n\
412 addKeyByPassphrase(passphrase, newPassphrase, slot)\n\n\
413 passphrase - string or none to ask the user\n\
414 newPassphrase - passphrase to add\n\
415 slot - which slot to use (optional)"
417 static PyObject *CryptSetup_addKeyByPassphrase(CryptSetupObject* self, PyObject *args, PyObject *kwds)
419 static char *kwlist[] = {"passphrase", "newPassphrase", "slot", NULL};
420 char *passphrase = NULL, *newpassphrase = NULL;
421 size_t passphrase_len = 0, newpassphrase_len = 0;
422 int slot = CRYPT_ANY_SLOT;
424 if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss|i", kwlist, &passphrase, &newpassphrase, &slot))
428 passphrase_len = strlen(passphrase);
431 newpassphrase_len = strlen(newpassphrase);
433 return PyObjectResult(crypt_keyslot_add_by_passphrase(self->device, slot,
434 passphrase, passphrase_len,
435 newpassphrase, newpassphrase_len));
438 #define CryptSetup_addKeyByVolumeKey_HELP "Initialize keyslot using cached volume key\n\n\
439 addKeyByVolumeKey(passphrase, newPassphrase, slot)\n\n\
440 newPassphrase - passphrase to add\n\
441 slot - which slot to use (optional)"
443 static PyObject *CryptSetup_addKeyByVolumeKey(CryptSetupObject* self, PyObject *args, PyObject *kwds)
445 static char *kwlist[] = {"newPassphrase", "slot", NULL};
446 char *newpassphrase = NULL;
447 size_t newpassphrase_len = 0;
448 int slot = CRYPT_ANY_SLOT;
450 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwlist, &newpassphrase, &slot))
454 newpassphrase_len = strlen(newpassphrase);
456 return PyObjectResult(crypt_keyslot_add_by_volume_key(self->device, slot,
457 NULL, 0, newpassphrase, newpassphrase_len));
460 #define CryptSetup_removePassphrase_HELP "Destroy keyslot using passphrase\n\n\
461 removePassphrase(passphrase)\n\n\
462 passphrase - string or none to ask the user"
464 static PyObject *CryptSetup_removePassphrase(CryptSetupObject* self, PyObject *args, PyObject *kwds)
466 static char *kwlist[] = {"passphrase", NULL};
467 char *passphrase = NULL;
468 size_t passphrase_len = 0;
471 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &passphrase))
475 passphrase_len = strlen(passphrase);
477 is = crypt_activate_by_passphrase(self->device, NULL, CRYPT_ANY_SLOT,
478 passphrase, passphrase_len, 0);
480 return PyObjectResult(is);
482 return PyObjectResult(crypt_keyslot_destroy(self->device, is));
485 #define CryptSetup_killSlot_HELP "Destroy keyslot\n\n\
487 slot - the slot to remove"
489 static PyObject *CryptSetup_killSlot(CryptSetupObject* self, PyObject *args, PyObject *kwds)
491 static char *kwlist[] = {"slot", NULL};
492 int slot = CRYPT_ANY_SLOT;
494 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &slot))
497 switch (crypt_keyslot_status(self->device, slot)) {
498 case CRYPT_SLOT_ACTIVE:
499 return PyObjectResult(crypt_keyslot_destroy(self->device, slot));
500 case CRYPT_SLOT_ACTIVE_LAST:
501 PyErr_SetString(PyExc_ValueError, "Last slot, removing it would render the device unusable");
503 case CRYPT_SLOT_INACTIVE:
504 PyErr_SetString(PyExc_ValueError, "Inactive slot");
506 case CRYPT_SLOT_INVALID:
507 PyErr_SetString(PyExc_ValueError, "Invalid slot");
514 #define CryptSetup_Status_HELP "Status of LUKS device\n\n\
517 static PyObject *CryptSetup_Status(CryptSetupObject* self, PyObject *args, PyObject *kwds)
519 if (!self->activated_as){
520 PyErr_SetString(PyExc_IOError, "Device has not been activated yet.");
524 return PyObjectResult(crypt_status(self->device, self->activated_as));
527 #define CryptSetup_Resume_HELP "Resume LUKS device\n\n\
528 luksOpen(passphrase)\n\n\
529 passphrase - string or none to ask the user"
531 static PyObject *CryptSetup_Resume(CryptSetupObject* self, PyObject *args, PyObject *kwds)
533 static char *kwlist[] = {"passphrase", NULL};
534 char* passphrase = NULL;
535 size_t passphrase_len = 0;
537 if (!self->activated_as){
538 PyErr_SetString(PyExc_IOError, "Device has not been activated yet.");
542 if (! PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, &passphrase))
546 passphrase_len = strlen(passphrase);
548 return PyObjectResult(crypt_resume_by_passphrase(self->device, self->activated_as,
549 CRYPT_ANY_SLOT, passphrase, passphrase_len));
552 #define CryptSetup_Suspend_HELP "Suspend LUKS device\n\n\
555 static PyObject *CryptSetup_Suspend(CryptSetupObject* self, PyObject *args, PyObject *kwds)
557 if (!self->activated_as){
558 PyErr_SetString(PyExc_IOError, "Device has not been activated yet.");
562 return PyObjectResult(crypt_suspend(self->device, self->activated_as));
565 #define CryptSetup_debugLevel_HELP "Set debug level\n\n\
566 debugLevel(level)\n\n\
569 static PyObject *CryptSetup_debugLevel(CryptSetupObject* self, PyObject *args, PyObject *kwds)
571 static char *kwlist[] = {"level", NULL};
574 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &level))
577 crypt_set_debug_level(level);
582 #define CryptSetup_iterationTime_HELP "Set iteration time\n\n\
583 iterationTime(time_ms)\n\n\
584 time_ms - time in miliseconds"
586 static PyObject *CryptSetup_iterationTime(CryptSetupObject* self, PyObject *args, PyObject *kwds)
588 static char *kwlist[] = {"time_ms", NULL};
589 uint64_t time_ms = 0;
591 if (!PyArg_ParseTupleAndKeywords(args, kwds, "K", kwlist, &time_ms))
594 crypt_set_iteration_time(self->device, time_ms);
599 static PyMemberDef CryptSetup_members[] = {
600 {"yesDialogCB", T_OBJECT_EX, offsetof(CryptSetupObject, yesDialogCB), 0, "confirmation dialog callback"},
601 {"cmdLineLogCB", T_OBJECT_EX, offsetof(CryptSetupObject, cmdLineLogCB), 0, "logging callback"},
602 {"passwordDialogCB", T_OBJECT_EX, offsetof(CryptSetupObject, passwordDialogCB), 0, "password dialog callback"},
606 static PyMethodDef CryptSetup_methods[] = {
607 /* self-test methods */
608 {"log", (PyCFunction)CryptSetup_log, METH_VARARGS|METH_KEYWORDS, CryptSetup_askyes_HELP},
609 {"askyes", (PyCFunction)CryptSetup_askyes, METH_VARARGS|METH_KEYWORDS, CryptSetup_log_HELP},
611 /* activation and deactivation */
612 {"deactivate", (PyCFunction)CryptSetup_deactivate, METH_NOARGS, CryptSetup_deactivate_HELP},
613 {"activate", (PyCFunction)CryptSetup_activate, METH_VARARGS|METH_KEYWORDS, CryptSetup_activate_HELP},
615 /* cryptsetup info entrypoints */
616 {"luksUUID", (PyCFunction)CryptSetup_luksUUID, METH_NOARGS, CryptSetup_luksUUID_HELP},
617 {"isLuks", (PyCFunction)CryptSetup_isLuks, METH_NOARGS, CryptSetup_isLuks_HELP},
618 {"info", (PyCFunction)CryptSetup_Info, METH_NOARGS, CryptSetup_Info_HELP},
619 {"status", (PyCFunction)CryptSetup_Status, METH_NOARGS, CryptSetup_Status_HELP},
621 /* cryptsetup mgmt entrypoints */
622 {"luksFormat", (PyCFunction)CryptSetup_luksFormat, METH_VARARGS|METH_KEYWORDS, CryptSetup_luksFormat_HELP},
623 {"addKeyByPassphrase", (PyCFunction)CryptSetup_addKeyByPassphrase, METH_VARARGS|METH_KEYWORDS, CryptSetup_addKeyByPassphrase_HELP},
624 {"addKeyByVolumeKey", (PyCFunction)CryptSetup_addKeyByVolumeKey, METH_VARARGS|METH_KEYWORDS, CryptSetup_addKeyByVolumeKey_HELP},
625 {"removePassphrase", (PyCFunction)CryptSetup_removePassphrase, METH_VARARGS|METH_KEYWORDS, CryptSetup_removePassphrase_HELP},
626 {"killSlot", (PyCFunction)CryptSetup_killSlot, METH_VARARGS|METH_KEYWORDS, CryptSetup_killSlot_HELP},
629 {"resume", (PyCFunction)CryptSetup_Resume, METH_VARARGS|METH_KEYWORDS, CryptSetup_Resume_HELP},
630 {"suspend", (PyCFunction)CryptSetup_Suspend, METH_NOARGS, CryptSetup_Suspend_HELP},
633 {"debugLevel", (PyCFunction)CryptSetup_debugLevel, METH_VARARGS|METH_KEYWORDS, CryptSetup_debugLevel_HELP},
634 {"iterationTime", (PyCFunction)CryptSetup_iterationTime, METH_VARARGS|METH_KEYWORDS, CryptSetup_iterationTime_HELP},
636 {NULL} /* Sentinel */
639 static PyTypeObject CryptSetupType = {
640 PyObject_HEAD_INIT(NULL)
642 "pycryptsetup.CryptSetup", /*tp_name*/
643 sizeof(CryptSetupObject), /*tp_basicsize*/
645 (destructor)CryptSetup_dealloc, /*tp_dealloc*/
652 0, /*tp_as_sequence*/
660 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
661 CryptSetup_HELP, /* tp_doc */
664 0, /* tp_richcompare */
665 0, /* tp_weaklistoffset */
668 CryptSetup_methods, /* tp_methods */
669 CryptSetup_members, /* tp_members */
673 0, /* tp_descr_get */
674 0, /* tp_descr_set */
675 0, /* tp_dictoffset */
676 (initproc)CryptSetup_init, /* tp_init */
678 CryptSetup_new, /* tp_new */
681 static PyMethodDef pycryptsetup_methods[] = {
682 {NULL} /* Sentinel */
685 PyMODINIT_FUNC initpycryptsetup(void);
686 PyMODINIT_FUNC initpycryptsetup(void)
690 if (PyType_Ready(&CryptSetupType) < 0)
693 m = Py_InitModule3("pycryptsetup", pycryptsetup_methods, "CryptSetup pythonized API.");
694 Py_INCREF(&CryptSetupType);
696 PyModule_AddObject(m, "CryptSetup", (PyObject *)&CryptSetupType);
698 /* debug constants */
699 PyModule_AddIntConstant(m, "CRYPT_DEBUG_ALL", CRYPT_DEBUG_ALL);
700 PyModule_AddIntConstant(m, "CRYPT_DEBUG_NONE", CRYPT_DEBUG_NONE);
703 PyModule_AddIntConstant(m, "CRYPT_LOG_NORMAL", CRYPT_LOG_NORMAL);
704 PyModule_AddIntConstant(m, "CRYPT_LOG_ERROR", CRYPT_LOG_ERROR);
705 PyModule_AddIntConstant(m, "CRYPT_LOG_VERBOSE", CRYPT_LOG_VERBOSE);
706 PyModule_AddIntConstant(m, "CRYPT_LOG_DEBUG", CRYPT_LOG_DEBUG);
708 /* status constants */
709 PyModule_AddIntConstant(m, "CRYPT_INVALID", CRYPT_INVALID);
710 PyModule_AddIntConstant(m, "CRYPT_INACTIVE", CRYPT_INACTIVE);
711 PyModule_AddIntConstant(m, "CRYPT_ACTIVE", CRYPT_ACTIVE);
712 PyModule_AddIntConstant(m, "CRYPT_BUSY", CRYPT_BUSY);