2
* Python bindings to libcryptsetup
4
* Copyright (C) 2009-2011, 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);