summaryrefslogtreecommitdiff
path: root/python/pwquality.c
diff options
context:
space:
mode:
Diffstat (limited to 'python/pwquality.c')
-rw-r--r--python/pwquality.c396
1 files changed, 396 insertions, 0 deletions
diff --git a/python/pwquality.c b/python/pwquality.c
new file mode 100644
index 0000000..e60152f
--- /dev/null
+++ b/python/pwquality.c
@@ -0,0 +1,396 @@
+/*
+ * libpwquality Python bindings
+ *
+ * Copyright (c) Red Hat, Inc, 2011
+ * Copyright (c) Tomas Mraz <tm@t8m.info>, 2011
+ *
+ * See the end of the file for the License Information
+ */
+
+#include <Python.h>
+#include "pwquality.h"
+
+static PyObject *PWQError;
+
+typedef struct {
+ PyObject_HEAD
+ pwquality_settings_t *pwq;
+} PWQSettings;
+
+static PyObject *
+pwqsettings_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
+static void
+pwqsettings_dealloc(PWQSettings *self);
+static PyObject *
+pwqsettings_getint(PWQSettings *self, void *setting);
+static int
+pwqsettings_setint(PWQSettings *self, PyObject *value, void *setting);
+static PyObject *
+pwqsettings_getstr(PWQSettings *self, void *setting);
+static int
+pwqsettings_setstr(PWQSettings *self, PyObject *value, void *setting);
+static PyObject *
+read_config(PWQSettings *self, PyObject *args);
+static PyObject *
+set_option(PWQSettings *self, PyObject *args);
+static PyObject *
+generate(PWQSettings *self, PyObject *args);
+static PyObject *
+check(PWQSettings *self, PyObject *args);
+
+static PyMethodDef pwqsettings_methods[] = {
+ { "read_config", (PyCFunction)read_config, METH_VARARGS,
+ "Read the settings from configuration file"
+ },
+ { "set_option", (PyCFunction)set_option, METH_VARARGS,
+ "Set option from name=value pair"
+ },
+ { "generate", (PyCFunction)generate, METH_VARARGS,
+ "Generate password with requested entropy"
+ },
+ { "check", (PyCFunction)check, METH_VARARGS,
+ "Check whether the password conforms to the requirements and return password strength score"
+ },
+ { NULL } /* Sentinel */
+};
+
+static PyGetSetDef pwqsettings_getseters[] = {
+ { "difok",
+ (getter)pwqsettings_getint, (setter)pwqsettings_setint,
+ "Minimum difference from the old password",
+ (void *)PWQ_SETTING_DIFF_OK
+ },
+ { "minlen",
+ (getter)pwqsettings_getint, (setter)pwqsettings_setint,
+ "Minimum length of the new password",
+ (void *)PWQ_SETTING_MIN_LENGTH
+ },
+ { "dcredit",
+ (getter)pwqsettings_getint, (setter)pwqsettings_setint,
+ "Credit for or minimum of digits",
+ (void *)PWQ_SETTING_DIG_CREDIT
+ },
+ { "ucredit",
+ (getter)pwqsettings_getint, (setter)pwqsettings_setint,
+ "Credit for or minimum of uppercase characters",
+ (void *)PWQ_SETTING_UP_CREDIT
+ },
+ { "lcredit",
+ (getter)pwqsettings_getint, (setter)pwqsettings_setint,
+ "Credit for or minimum of lowercase characters",
+ (void *)PWQ_SETTING_LOW_CREDIT
+ },
+ { "ocredit",
+ (getter)pwqsettings_getint, (setter)pwqsettings_setint,
+ "Credit for or minimum of other characters",
+ (void *)PWQ_SETTING_OTH_CREDIT
+ },
+ { "minclass",
+ (getter)pwqsettings_getint, (setter)pwqsettings_setint,
+ "Minimum number of character classes",
+ (void *)PWQ_SETTING_MIN_CLASS
+ },
+ { "maxrepeat",
+ (getter)pwqsettings_getint, (setter)pwqsettings_setint,
+ "Maximum repeated consecutive characters",
+ (void *)PWQ_SETTING_MAX_REPEAT
+ },
+ { "dictpath",
+ (getter)pwqsettings_getstr, (setter)pwqsettings_setstr,
+ "Path to the cracklib dictionary",
+ (void *)PWQ_SETTING_DICT_PATH
+ },
+ { NULL } /* Sentinel */
+};
+
+
+static PyTypeObject pwqsettings_type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "pwquality.PWQSettings", /* tp_name */
+ sizeof(PWQSettings), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)pwqsettings_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ "PWQSettings objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ pwqsettings_methods, /* tp_methods */
+ 0, /* tp_members */
+ pwqsettings_getseters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ pwqsettings_new, /* tp_new */
+};
+
+static PyMethodDef pwquality_methods[] = {
+ { NULL } /* Sentinel */
+};
+
+static PyObject *
+pwqerror(int rc, void *auxerror)
+{
+ char buf[PWQ_MAX_ERROR_MESSAGE_LEN];
+ PyObject *py_errvalue;
+ const char *msg;
+
+ msg = pwquality_strerror(buf, sizeof(buf), rc, auxerror);
+
+ if (rc == PWQ_ERROR_MEM_ALLOC)
+ return PyErr_NoMemory();
+
+ py_errvalue = Py_BuildValue("is", rc, msg);
+ if (py_errvalue == NULL)
+ return NULL;
+
+ if (rc == PWQ_ERROR_UNKNOWN_SETTING || rc == PWQ_ERROR_NON_INT_SETTING
+ || rc == PWQ_ERROR_NON_STR_SETTING) {
+ PyErr_SetObject(PyExc_AttributeError, py_errvalue);
+ } else {
+ PyErr_SetObject(PWQError, py_errvalue);
+ }
+ return NULL;
+}
+
+static PyObject *
+pwqsettings_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PWQSettings *self;
+
+ self = (PWQSettings *)type->tp_alloc(type, 0);
+ if (self) {
+ self->pwq = pwquality_default_settings();
+ if (self->pwq == NULL) {
+ Py_DECREF(self);
+ return PyErr_NoMemory();
+ }
+ }
+ return (PyObject *)self;
+}
+
+static void
+pwqsettings_dealloc(PWQSettings *self)
+{
+ pwquality_free_settings(self->pwq);
+ self->ob_type->tp_free((PyObject *)self);
+}
+
+static PyObject *
+pwqsettings_getint(PWQSettings *self, void *setting)
+{
+ int value;
+ int rc;
+
+ if ((rc = pwquality_get_int_value(self->pwq, (int)(ssize_t)setting, &value)) < 0) {
+ return pwqerror(rc, NULL);
+ }
+ return PyInt_FromLong((long)value);
+}
+
+static int
+pwqsettings_setint(PWQSettings *self, PyObject *value, void *setting)
+{
+ long l;
+ int rc;
+
+ l = PyInt_AsLong(value);
+ if (PyErr_Occurred() == NULL) {
+ if ((rc = pwquality_set_int_value(self->pwq,
+ (int)(ssize_t)setting, (int)l)) < 0) {
+ pwqerror(rc, NULL);
+ return -1;
+ }
+ return 0;
+ }
+ return -1;
+}
+
+static PyObject *
+pwqsettings_getstr(PWQSettings *self, void *setting)
+{
+ const char *value;
+ int rc;
+
+ if ((rc = pwquality_get_str_value(self->pwq, (int)(ssize_t)setting, &value)) < 0) {
+ return pwqerror(rc, NULL);
+ }
+ if (value == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return PyString_FromString(value);
+}
+
+static int
+pwqsettings_setstr(PWQSettings *self, PyObject *value, void *setting)
+{
+ const char *s;
+ int rc;
+
+ if (value == (PyObject *)Py_None)
+ s = NULL;
+ else
+ s = PyString_AsString(value);
+
+ if (PyErr_Occurred() == NULL) {
+ if ((rc = pwquality_set_str_value(self->pwq,
+ (int)(ssize_t)setting, s)) < 0) {
+ pwqerror(rc, NULL);
+ return -1;
+ }
+ return 0;
+ }
+ return -1;
+}
+
+static PyObject *
+read_config(PWQSettings *self, PyObject *args)
+{
+ char *cfgfile = NULL;
+ void *auxerror;
+ int rc;
+
+ if (!PyArg_ParseTuple(args, "|s", &cfgfile))
+ return NULL;
+ if ((rc = pwquality_read_config(self->pwq, cfgfile, &auxerror)) < 0) {
+ return pwqerror(rc, auxerror);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+set_option(PWQSettings *self, PyObject *args)
+{
+ char *option;
+ int rc;
+
+ if (!PyArg_ParseTuple(args, "s", &option))
+ return NULL;
+ if ((rc = pwquality_set_option(self->pwq, option)) < 0) {
+ return pwqerror(rc, NULL);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+generate(PWQSettings *self, PyObject *args)
+{
+ int entropy_bits;
+ char *password;
+ PyObject *passobj;
+ int rc;
+
+ if (!PyArg_ParseTuple(args, "i", &entropy_bits))
+ return NULL;
+ if ((rc = pwquality_generate(self->pwq, entropy_bits, &password)) < 0) {
+ return pwqerror(rc, NULL);
+ }
+
+ passobj = PyString_FromString(password);
+ free(password);
+ return passobj;
+}
+
+static PyObject *
+check(PWQSettings *self, PyObject *args)
+{
+ char *password;
+ char *oldpassword = NULL;
+ char *username = NULL;
+ void *auxerror;
+ int rc;
+
+ if (!PyArg_ParseTuple(args, "s|ss", &password, &oldpassword, &username))
+ return NULL;
+ if ((rc = pwquality_check(self->pwq, password, oldpassword,
+ username, &auxerror)) < 0) {
+ return pwqerror(rc, auxerror);
+ }
+
+ return PyInt_FromLong((long)rc);
+}
+
+PyMODINIT_FUNC
+initpwquality(void)
+{
+ PyObject *module;
+
+ if (PyType_Ready(&pwqsettings_type) < 0)
+ return;
+
+ module = Py_InitModule3("pwquality", pwquality_methods,
+ "Libpwquality wrapper module");
+ if (module == NULL)
+ return;
+
+ PWQError = PyErr_NewException("pwquality.PWQError", NULL, NULL);
+ if (PWQError == NULL) {
+ Py_DECREF(module);
+ return;
+ }
+ Py_INCREF(PWQError);
+ PyModule_AddObject(module, "PWQError", PWQError);
+
+ Py_INCREF(&pwqsettings_type);
+ PyModule_AddObject(module, "PWQSettings", (PyObject *)&pwqsettings_type);
+
+#include "constants.c"
+}
+
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */