changeset 09539d472e81 in /srv/hg/libpwquality
details:
http://hg.fedorahosted.org/hg/srv/hg/libpwquality?cmd=changeset;node=0953...
summary: Add Python interface for libpwquality.
diffstat:
.hgignore | 2 +
Makefile.am | 2 +-
configure.in | 10 +-
python/Makefile.am | 16 ++
python/pwquality.c | 396 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
python/setup.py | 74 ++++++++++
6 files changed, 498 insertions(+), 2 deletions(-)
diffs (544 lines):
diff -r 7cf418d178ec -r 09539d472e81 .hgignore
--- a/.hgignore Mon Nov 07 15:13:10 2011 +0100
+++ b/.hgignore Mon Nov 07 17:42:00 2011 +0100
@@ -37,3 +37,5 @@
po/remove-*
src/pwmake
src/pwscore
+python/constants.c
+python/pwquality.so
diff -r 7cf418d178ec -r 09539d472e81 Makefile.am
--- a/Makefile.am Mon Nov 07 15:13:10 2011 +0100
+++ b/Makefile.am Mon Nov 07 17:42:00 2011 +0100
@@ -6,7 +6,7 @@
AUTOMAKE_OPTIONS = 1.9 gnu dist-bzip2 check-news
-SUBDIRS = po src
+SUBDIRS = po src python
CLEANFILES = *~
diff -r 7cf418d178ec -r 09539d472e81 configure.in
--- a/configure.in Mon Nov 07 15:13:10 2011 +0100
+++ b/configure.in Mon Nov 07 17:42:00 2011 +0100
@@ -88,6 +88,14 @@
AC_SUBST(SCONFIGDIR)
dnl options and defaults
+AC_ARG_WITH(python-rev,
+ [ --with-pythonrev=2.7 version of python for which modules should be
built],
+ PYTHONREV=$withval,[
+ AC_MSG_CHECKING([python version])
+ [PYTHONREV=`python -c 'import sys;print "%s.%s" %
(sys.version_info[0], sys.version_info[1])'`]
+ AC_MSG_RESULT($PYTHONREV)
+ ])
+AC_SUBST(PYTHONREV)
dnl Check for cracklib
AC_CHECK_HEADERS([crack.h],
@@ -111,5 +119,5 @@
AC_CHECK_FUNCS(strcspn strdup strspn strstr strtol)
dnl Files to be created from when we run configure
-AC_CONFIG_FILES([Makefile libpwquality.spec src/Makefile po/Makefile.in])
+AC_CONFIG_FILES([Makefile libpwquality.spec src/Makefile po/Makefile.in
python/Makefile])
AC_OUTPUT
diff -r 7cf418d178ec -r 09539d472e81 python/Makefile.am
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python/Makefile.am Mon Nov 07 17:42:00 2011 +0100
@@ -0,0 +1,16 @@
+#
+# Copyright (c) 2011 Red Hat, Inc.
+# Copyright (c) 2011 Tomas Mraz <tm(a)t8m.info>
+#
+
+pythonincdir = $(includedir)/python@PYTHONREV@
+pythonsitedir = $(libdir)/python@PYTHONREV@/site-packages
+
+CLEANFILES = *~ constants.c pwquality.so
+
+EXTRA_DIST = pwquality.c setup.py
+
+pythonsite_SCRIPTS = pwquality.so
+
+pwquality.so: ../src/pwquality.h pwquality.c setup.py
+ python setup.py build --build-lib=.
diff -r 7cf418d178ec -r 09539d472e81 python/pwquality.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python/pwquality.c Mon Nov 07 17:42:00 2011 +0100
@@ -0,0 +1,396 @@
+/*
+ * libpwquality Python bindings
+ *
+ * Copyright (c) Red Hat, Inc, 2011
+ * Copyright (c) Tomas Mraz <tm(a)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.
+ */
diff -r 7cf418d178ec -r 09539d472e81 python/setup.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/python/setup.py Mon Nov 07 17:42:00 2011 +0100
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# See the end of the file for Copyright and License Information
+#
+
+from distutils.core import setup, Extension
+from distutils.command.build_ext import build_ext as _build_ext
+
+class build_ext(_build_ext):
+ def genconstants(self, headerfile, outputfile):
+ hf = open(headerfile, 'r')
+ of = open(outputfile, 'w')
+ of.write('/* This file is generated during build time from pwquality.h
*/\n\n')
+ for line in hf:
+ if line.startswith('#define PWQ_'):
+ s = line.split()
+ of.write('PyModule_AddIntConstant(module, "%s",
%s);\n' % (s[1], s[2]))
+
+ def run(self):
+ self.genconstants('../src/pwquality.h', 'constants.c')
+ _build_ext.run(self)
+
+pwqmodule = Extension('pwquality',
+ sources = ['pwquality.c'],
+ include_dirs = ['../src'],
+ library_dirs = ['../src/.libs'],
+ libraries = ['pwquality'])
+
+setup(
+ name = 'pwquality',
+ version = '0.9.1',
+ description = 'Python bindings for the libpwquality library for password quality
checking',
+ author = 'Tomáš Mráz',
+ author_email = 'tm(a)t8m.info',
+ url = 'http://fedorahosted.org/libpwquality',
+ license = 'BSD or GPL+',
+ ext_modules = [pwqmodule],
+ cmdclass = {'build_ext': build_ext}
+)
+
+# Copyright (c) Red Hat, Inc, 2011
+# Copyright (c) Tomas Mraz <tm(a)t8m.info>, 2011
+#
+# 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.