aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2008-03-13 13:53:32 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2008-03-13 13:53:32 +0000
commit222d4ff80720206deeb8e7ee87831812628329af (patch)
treeccf4a8ed8e19e8b9b1c33b6a27cb95f51b1ec256
parentf9f6f80133f16fb1fc6c064bee5fe5c53a17c9d8 (diff)
downloadpam-modules-222d4ff80720206deeb8e7ee87831812628329af.tar.gz
pam-modules-222d4ff80720206deeb8e7ee87831812628329af.tar.bz2
* configure.ac (PAM_COMMON_INCLUDES): Add -I${top_srcdir}/lib.
(AC_OUTPUT): Add lib/Makefile. * doc/pam-modules.texi: Document `transform' option. * Make.rules: New file. * lib/mem.c, lib/slist.c, lib/log.c, lib/converse.c, lib/graypam.h, lib/Makefile.am, lib/transform.c. * pam_regex/pam_regex.c: Implement user name transformations. * pam_fshadow/Makefile.am, pam_sql/Makefile.am: Add ../lib/libgraypam.la to LDADD * pam_fshadow/pam_fshadow.c, pam_sql/pam_mysql.c, pam_sql/pam_pgsql.c, pam_sql/pam_sql.c: Use functions from ../lib. git-svn-id: file:///svnroot/pam-modules/trunk@63 56984be4-0537-0410-a56c-fcb268c96130
-rw-r--r--ChangeLog17
-rw-r--r--Make.rules26
-rw-r--r--Makefile.am5
-rw-r--r--NEWS14
-rw-r--r--common.c150
-rw-r--r--configure.ac5
-rw-r--r--doc/pam-modules.texi80
-rw-r--r--lib/Makefile.am19
-rw-r--r--lib/converse.c49
-rw-r--r--lib/graypam.h149
-rw-r--r--lib/log.c79
-rw-r--r--lib/mem.c99
-rw-r--r--lib/slist.c244
-rw-r--r--lib/transform.c533
-rw-r--r--pam_fshadow/Makefile.am15
-rw-r--r--pam_fshadow/pam_fshadow.c97
-rw-r--r--pam_log/Makefile.am15
-rw-r--r--pam_log/pam_log.c79
-rw-r--r--pam_regex/Makefile.am18
-rw-r--r--pam_regex/pam_regex.c150
-rw-r--r--pam_sql/Makefile.am3
-rw-r--r--pam_sql/pam_mysql.c15
-rw-r--r--pam_sql/pam_pgsql.c15
-rw-r--r--pam_sql/pam_sql.c79
24 files changed, 1475 insertions, 480 deletions
diff --git a/ChangeLog b/ChangeLog
index e2fb656..80ebb18 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,23 @@
+2008-03-13 Sergey Poznyakoff <gray@gnu.org.ua>
+
+ * configure.ac (PAM_COMMON_INCLUDES): Add -I${top_srcdir}/lib.
+ (AC_OUTPUT): Add lib/Makefile.
+ * doc/pam-modules.texi: Document `transform' option.
+ * Make.rules: New file.
+
+ * lib/mem.c, lib/slist.c, lib/log.c, lib/converse.c,
+ lib/graypam.h, lib/Makefile.am, lib/transform.c.
+
+ * pam_regex/pam_regex.c: Implement user name transformations.
+
+ * pam_fshadow/Makefile.am, pam_sql/Makefile.am:
+ Add ../lib/libgraypam.la to LDADD
+ * pam_fshadow/pam_fshadow.c, pam_sql/pam_mysql.c,
+ pam_sql/pam_pgsql.c, pam_sql/pam_sql.c: Use functions from ../lib.
+
2007-08-28 Sergey Poznyakoff <gray@gnu.org.ua>
* pam_fshadow/Makefile.am, pam_regex/Makefile.am,
pam_log/Makefile.am: Place INCLUDES in front of CPPFLAGS
* pam_sql/Makefile.am: Place INCLUDES in front of CPPFLAGS
diff --git a/Make.rules b/Make.rules
new file mode 100644
index 0000000..ecf28eb
--- /dev/null
+++ b/Make.rules
@@ -0,0 +1,26 @@
+# Copyright (C) 2001, 2006, 2007 Sergey Poznyakoff
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+
+.c.lo:
+ $(LIBTOOL) --mode=compile $(CC) -c -DHAVE_CONFIG_H \
+ $(CFLAGS) $(AM_CFLAGS) $(INCLUDES) $(CPPFLAGS) \
+ $(AM_CPPFLAGS) $<
+
+.lo.la:
+ $(LIBTOOL) --mode=link $(CC) -module -export-dynamic \
+ $(AM_LDFLAGS) \
+ -o $@ $< $(AM_LDADD) $(LDADD) \
+ -rpath $(pamdir) -shared
+
diff --git a/Makefile.am b/Makefile.am
index 0434695..7885d82 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
-# Copyright (C) 2001, 2006 Sergey Poznyakoff
+# Copyright (C) 2001, 2006, 2008 Sergey Poznyakoff
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
@@ -11,8 +11,7 @@
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
AUTOMAKE_OPTIONS = gnits 1.8
-SUBDIRS = doc pam_fshadow pam_regex pam_log pam_sql
-EXTRA_DIST=common.c
+SUBDIRS = doc lib pam_fshadow pam_regex pam_log pam_sql
diff --git a/NEWS b/NEWS
index 763e42c..7b01934 100644
--- a/NEWS
+++ b/NEWS
@@ -1,15 +1,19 @@
-pam-modules -- history of user-visible changes. 2007-08-14
-Copyright (C) 2001,2004,2005,2007 Sergey Poznyakoff
+pam-modules -- history of user-visible changes. 2008-03-13
+Copyright (C) 2001,2004,2005,2007,2008 Sergey Poznyakoff
See the end of file for copying conditions.
Please send radius bug reports to <bug-pam-modules@gnu.org.ua>
-Version 1.2, CVS
+Version 1.2, SVN
-Several fixes in debugging code and pam_mysql, pam_pgsql modules.
+* Several fixes in debugging code and pam_mysql, pam_pgsql modules.
+
+* pam_regex transform=expr
+
+New command line option `transform' allows to rewrite user names.
Version 1.1, 2007-08-11
* pam_fshadow allows to use virtual domains to specify alternate password
databases. New options: regex, basic, extended, ignore-case, icase
@@ -34,13 +38,13 @@ Version 0.1
Initial release. See README for short description.
^L
=========================================================================
Copyright information:
-Copyright (C) 2001,2004,2005 Sergey Poznyakoff
+Copyright (C) 2001,2004,2005,2007,2008 Sergey Poznyakoff
Permission is granted to anyone to make or distribute verbatim copies
of this document as received, in any medium, provided that the
copyright notice and this permission notice are preserved,
thus giving the recipient permission to redistribute in turn.
diff --git a/common.c b/common.c
deleted file mode 100644
index 6004929..0000000
--- a/common.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/* This file is part of pam-modules.
- Copyright (C) 2001, 2007 Sergey Poznyakoff
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 3 of the License, or (at your
- option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#ifndef PAM_CONV_AGAIN
-# define PAM_CONV_AGAIN PAM_TRY_AGAIN
-#endif
-#ifndef PAM_AUTHTOK_RECOVER_ERR
-# define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR
-#endif
-#ifndef PAM_EXTERN
-# define PAM_EXTERN
-#endif
-
-#include <regex.h>
-
-#define XSTRDUP(s) (s) ? strdup(s) : NULL
-
-#define PAM_OVERWRITE(s) \
- do { \
- register char *p; \
- if ((p = s) != NULL) \
- while (*p) *p++ = 0; \
- } while (0)
-
-#define PAM_DROP_REPLY(reply, nrepl) \
- do { \
- int i; \
- for (i=0; i<nrepl; i++) { \
- PAM_OVERWRITE(reply[i].resp); \
- free(reply[i].resp); \
- } \
- if (reply) \
- free(reply); \
- } while (0)
-
-static void
-_pam_delete(char *x)
-{
- PAM_OVERWRITE(x);
- free(x);
-}
-
-static void
-_cleanup_string(pam_handle_t *pamh, void *x, int error_status)
-{
- _pam_delete(x);
-}
-
-static void
-_cleanup_regex(pam_handle_t *pamh, void *x, int error_status)
-{
- regfree((regex_t*)x);
-}
-
-static void _pam_log(int err, const char *format, ...);
-
-static void
-make_str(pam_handle_t *pamh, const char *str, const char *name, char **ret)
-{
- int retval;
- char *newstr = XSTRDUP(str);
-
- retval = pam_set_data(pamh, name, (void *)newstr, _cleanup_string);
- if (retval != PAM_SUCCESS) {
- _pam_log(LOG_CRIT,
- "can't keep data [%s]: %s",
- name,
- pam_strerror(pamh, retval));
- _pam_delete(newstr);
- } else {
- *ret = newstr;
- newstr = NULL;
- }
-}
-
-#define MAKE_STR(pamh, str, var) \
- make_str(pamh,str,#var,&var)
-
-/* Syslog functions */
-static int syslog_dont_open = 0;
-static const char *syslog_tag = MODULE_NAME;
-static int facility = LOG_AUTHPRIV;
-
-static void
-_pam_vlog(int err, const char *format, va_list args)
-{
- if (syslog_dont_open)
- err |= facility;
- else
- openlog(syslog_tag, LOG_CONS|LOG_PID, facility);
- vsyslog(err, format, args);
- if (!syslog_dont_open)
- closelog();
-}
-
-static void
-_pam_log(int err, const char *format, ...)
-{
- va_list args;
-
- va_start(args, format);
- _pam_vlog(err, format, args);
- va_end(args);
-}
-
-static void
-_pam_debug(const char *format, ...)
-{
- va_list args;
-
- va_start(args, format);
- _pam_vlog(LOG_DEBUG, format, args);
- va_end(args);
-}
-
-void
-wait_debug(size_t interval, const char *file, size_t line)
-{
-#ifdef DEBUG_MODE
- if (!interval)
- interval = 3600;
- _pam_log(LOG_CRIT, "WAITING FOR DEBUG AT %s:%d",
- file, (unsigned long)line);
- while (interval-- > 0)
- sleep(1);
-#else
- _pam_log(LOG_NOTICE, "Debugging is not configured");
-#endif
-}
-
-#define WAITDEBUG(arg) do { size_t line = __LINE__; \
- if ((arg)[0] == '=') \
- wait_debug(atoi((arg)+1), __FILE__, line); \
- else \
- wait_debug(0, __FILE__, line); \
-} while (0)
-
diff --git a/configure.ac b/configure.ac
index 00d84a5..7280b84 100644
--- a/configure.ac
+++ b/configure.ac
@@ -23,13 +23,13 @@ AM_INIT_AUTOMAKE(no-exeext)
AM_CONFIG_HEADER(config.h)
dnl Library versioning
AC_SUBST(VI_CURRENT,1)
AC_SUBST(VI_REVISION,0)
AC_SUBST(VI_AGE,0)
-AC_SUBST(PAM_COMMON_INCLUDES, '-I${top_builddir} -I${top_srcdir}')
+AC_SUBST(PAM_COMMON_INCLUDES, '-I${top_builddir} -I${top_srcdir} -I${top_srcdir}/lib')
dnl Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
AM_PROG_LIBTOOL
@@ -178,11 +178,12 @@ if test "$MYSQL" = no; then
enable_mysql=no
else
enable_mysql=yes
fi])
AC_OUTPUT(Makefile
- doc/Makefile
+ doc/Makefile
+ lib/Makefile
pam_fshadow/Makefile
pam_regex/Makefile
pam_log/Makefile
pam_sql/Makefile)
diff --git a/doc/pam-modules.texi b/doc/pam-modules.texi
index 1c94929..11b1037 100644
--- a/doc/pam-modules.texi
+++ b/doc/pam-modules.texi
@@ -268,15 +268,15 @@ for the user name @samp{smith} in the files
@node regex, log, fshadow, Top
@chapter Authentication using regular expressions.
@prindex pam_regex
The module @command{pam_regex} allows to control user access by
-matching their login name against a regular expression. It
-may be useful, for example, in authentication stacks for such services
-as @acronym{FTP} or @acronym{HTTP}.
+matching their login name against a regular expression and to alter
+user names. It may be useful, for example, in authentication stacks
+for such services as @acronym{FTP} or @acronym{HTTP}.
@table @code
@opindex basic, @command{pam_regex} option
@item basic
Use basic regular expression.
@@ -302,12 +302,86 @@ option is mandatory. The default expression flavor is
options (see above).
@opindex sense, @command{pam_regex} option
@item sense=@{allow|deny@}
What to do if user name matches the regexp. Default is @samp{allow}.
+@opindex transform, @command{pam_regex} option
+@item transform=@var{expression}
+ Transform the user name using given expression. The argument
+@var{expression} is a @command{sed}-like replace expression of the
+form:
+
+@smallexample
+s/@var{regexp}/@var{replace}/[@var{flags}]
+@end smallexample
+
+@noindent
+where @var{regexp} is a @dfn{regular expression}, @var{replace} is a
+replacement for each file name part that matches @var{regexp}. Both
+@var{regexp} and @var{replace} are described in detail in
+@ref{The "s" Command, The "s" Command, The `s' Command, sed, GNU sed}.
+
+As in @command{sed}, you can give several replace expressions,
+separated by a semicolon.
+
+Supported @var{flags} are:
+
+@table @samp
+@item g
+Apply the replacement to @emph{all} matches to the @var{regexp}, not
+just the first.
+
+@item i
+Use case-insensitive matching
+
+@item x
+@var{regexp} is an @dfn{extended regular expression} (@pxref{Extended
+regexps, Extended regular expressions, Extended regular expressions,
+sed, GNU sed}).
+
+@item @var{number}
+Only replace the @var{number}th match of the @var{regexp}.
+
+Note: the @var{posix} standard does not specify what should happen
+when you mix the @samp{g} and @var{number} modifiers. @command{Pam_regex}
+follows the GNU @command{sed} implementation in this regard, so
+the interaction is defined to be: ignore matches before the
+@var{number}th, and then match and replace all matches from the
+@var{number}th on.
+
+@end table
+
+Any delimiter can be used in lieue of @samp{/}, the only requirement being
+that it be used consistently throughout the expression. For example,
+the following two expressions are equivalent:
+
+@smallexample
+@group
+s/one/two/
+s,one,two,
+@end group
+@end smallexample
+
+Changing delimiters is often useful when the @var{regex} contains
+slashes. For instance, it is more convenient to write @code{s,/,-,} than
+@code{s/\//-/}.
+
+The following example converts the user name to
+lower case and removes anything after the @samp{@@} symbol. It allows
+allows only user names @samp{anoncvs} and @samp{anonymous}. As a
+result, the following user names will pass the module: @samp{anoncvs},
+@samp{Anoncvs}, @samp{AnonCVS@@user.org}.
+
+@smallexample
+@group
+pam_refex.so extended transform=s/.*/\L&/g;s/@.*/ \
+ regex=^(anoncvs|anonymous)$ sense=allow
+@end group
+@end smallexample
+
@opindex use_authtok, @command{pam_regex} option
@item use_authtok
Do not prompt the user for password, take it from the saved
authentication tokens instead. This option is useful when
@command{pam_fshadow} is used as a non-first module in a stack of
authentication modules.
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..1a5acea
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,19 @@
+# Copyright (C) 2008 Sergey Poznyakoff
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+
+lib_LTLIBRARIES = libgraypam.la
+
+libgraypam_la_SOURCES = log.c mem.c slist.c transform.c converse.c
+noinst_HEADERS = graypam.h \ No newline at end of file
diff --git a/lib/converse.c b/lib/converse.c
new file mode 100644
index 0000000..dc7c44d
--- /dev/null
+++ b/lib/converse.c
@@ -0,0 +1,49 @@
+/* This file is part of pam-modules.
+ Copyright (C) 2008 Sergey Poznyakoff
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <graypam.h>
+
+int
+gray_converse(pam_handle_t *pamh,
+ int nargs,
+ struct pam_message **message,
+ struct pam_response **response)
+{
+ int retval;
+ struct pam_conv *conv;
+
+ retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv);
+ if (retval == PAM_SUCCESS) {
+
+ retval = conv->conv(nargs,
+ (const struct pam_message **) message,
+ response,
+ conv->appdata_ptr);
+
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_ERR,
+ "conversation failure [%s]",
+ pam_strerror(pamh, retval));
+ }
+ } else if (retval != PAM_CONV_AGAIN) {
+ _pam_log(LOG_ERR,
+ "couldn't obtain coversation function: %s",
+ pam_strerror(pamh, retval));
+ }
+
+ return retval; /* propagate error status */
+}
+
diff --git a/lib/graypam.h b/lib/graypam.h
new file mode 100644
index 0000000..24b8ea7
--- /dev/null
+++ b/lib/graypam.h
@@ -0,0 +1,149 @@
+/* This file is part of pam-modules.
+ Copyright (C) 2008 Sergey Poznyakoff
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _graypam_h_
+#define _graypam_h_
+
+#if defined(HAVE_CONFIG_H)
+# include <config.h>
+#endif
+#ifdef HAVE__PAM_ACONF_H
+#include <security/_pam_aconf.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <syslog.h>
+#include <errno.h>
+#include <regex.h>
+#include <setjmp.h>
+
+#ifndef LINUX_PAM
+#include <security/pam_appl.h>
+#endif /* LINUX_PAM */
+#include <security/pam_modules.h>
+
+#ifndef PAM_CONV_AGAIN
+# define PAM_CONV_AGAIN PAM_TRY_AGAIN
+#endif
+#ifndef PAM_AUTHTOK_RECOVER_ERR
+# define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR
+#endif
+#ifndef PAM_EXTERN
+# define PAM_EXTERN
+#endif
+
+#define XSTRDUP(s) ((s) ? strdup(s) : NULL)
+
+#define PAM_OVERWRITE(s) \
+ do { \
+ register char *p; \
+ if ((p = s) != NULL) \
+ while (*p) *p++ = 0; \
+ } while (0)
+
+#define PAM_DROP_REPLY(reply, nrepl) \
+ do { \
+ int i; \
+ for (i=0; i<nrepl; i++) { \
+ PAM_OVERWRITE(reply[i].resp); \
+ free(reply[i].resp); \
+ } \
+ if (reply) \
+ free(reply); \
+ } while (0)
+
+
+#define MAKE_STR(pamh, str, var) \
+ gray_make_str(pamh,str,#var,&var)
+
+#define WAITDEBUG(arg) do { size_t line = __LINE__; \
+ if ((arg)[0] == '=') \
+ gray_wait_debug(atoi((arg)+1), __FILE__, line); \
+ else \
+ gray_wait_debug(0, __FILE__, line); \
+} while (0)
+
+extern jmp_buf gray_pam_jmp;
+
+#define gray_pam_init(retval) \
+ if (setjmp(gray_pam_jmp)) \
+ return retval; \
+
+void gray_raise(const char *fmt, ...);
+
+void *gray_malloc(size_t size);
+void *gray_zalloc(size_t size);
+void *gray_realloc(void *ptr, size_t size);
+
+void gray_pam_delete(char *x);
+void gray_cleanup_string(pam_handle_t *pamh, void *x, int error_status);
+void gray_cleanup_regex(pam_handle_t *pamh, void *x, int error_status);
+void gray_make_str(pam_handle_t *pamh, const char *str, const char *name,
+ char **ret);
+
+
+typedef struct gray_slist *gray_slist_t;
+
+gray_slist_t gray_slist_create();
+void gray_slist_clear(gray_slist_t slist);
+void gray_slist_free(gray_slist_t *slist);
+void gray_slist_append(gray_slist_t slist, const char *str, size_t n);
+void gray_slist_append_char(gray_slist_t slist, char c);
+size_t gray_slist_size(gray_slist_t slist);
+size_t gray_slist_coalesce(gray_slist_t slist);
+void *gray_slist_head(gray_slist_t slist, size_t *psize);
+void *gray_slist_finish(gray_slist_t slist);
+void gray_slist_grow_backslash_num(gray_slist_t slist, char *text, char **pend,
+ int len, int base);
+void gray_slist_grow_backslash(gray_slist_t slist, char *text, char **endp);
+
+
+void gray_log_init(int dont_open, const char *tag, int f);
+void gray_pam_vlog(int err, const char *format, va_list args);
+void gray_pam_log(int err, const char *format, ...);
+void gray_pam_debug(const char *format, ...);
+void gray_wait_debug(size_t interval, const char *file, size_t line);
+
+#define _pam_vlog gray_pam_vlog
+#define _pam_log gray_pam_log
+#define _pam_debug gray_pam_debug
+
+
+int gray_transform_name_to_slist (gray_slist_t slist, char *input, char **output);
+void gray_set_transform_expr (const char *expr);
+
+
+int gray_converse(pam_handle_t *pamh, int nargs,
+ struct pam_message **message,
+ struct pam_response **response);
+
+/* Command line parsing */
+#define CNTL_DEBUG 0x0001
+#define CNTL_AUDIT 0x0002
+#define CNTL_WAITDEBUG 0x0004
+
+#define CNTL_DEBUG_LEV() (cntl_flags>>16)
+#define CNTL_SET_DEBUG_LEV(cntl,n) (cntl |= ((n)<<16))
+
+#define DEBUG(m,c) if (CNTL_DEBUG_LEV()>=(m)) _pam_debug c
+#define AUDIT(c) if (cntl_flags&CNTL_AUDIT) _pam_debug c
+
+#endif
diff --git a/lib/log.c b/lib/log.c
new file mode 100644
index 0000000..2794c02
--- /dev/null
+++ b/lib/log.c
@@ -0,0 +1,79 @@
+/* This file is part of pam-modules.
+ Copyright (C) 2008 Sergey Poznyakoff
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <graypam.h>
+
+/* Syslog functions */
+static int syslog_dont_open;
+static const char *syslog_tag = "pam_modules";
+static int facility;
+
+void
+gray_log_init(int dont_open, const char *tag, int f)
+{
+ syslog_dont_open = dont_open;
+ syslog_tag = tag;
+ facility = f;
+}
+
+void
+gray_pam_vlog(int err, const char *format, va_list args)
+{
+ if (syslog_dont_open)
+ err |= facility;
+ else
+ openlog(syslog_tag, LOG_CONS|LOG_PID, facility);
+ vsyslog(err, format, args);
+ if (!syslog_dont_open)
+ closelog();
+}
+
+void
+gray_pam_log(int err, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ gray_pam_vlog(err, format, args);
+ va_end(args);
+}
+
+void
+gray_pam_debug(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ gray_pam_vlog(LOG_DEBUG, format, args);
+ va_end(args);
+}
+
+void
+gray_wait_debug(size_t interval, const char *file, size_t line)
+{
+#ifdef DEBUG_MODE
+ if (!interval)
+ interval = 3600;
+ gray_pam_log(LOG_CRIT, "WAITING FOR DEBUG AT %s:%d",
+ file, (unsigned long)line);
+ while (interval-- > 0)
+ sleep(1);
+#else
+ gray_pam_log(LOG_NOTICE, "Debugging is not configured");
+#endif
+}
+
+
diff --git a/lib/mem.c b/lib/mem.c
new file mode 100644
index 0000000..e8ee1cc
--- /dev/null
+++ b/lib/mem.c
@@ -0,0 +1,99 @@
+/* This file is part of pam-modules.
+ Copyright (C) 2008 Sergey Poznyakoff
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <graypam.h>
+
+jmp_buf gray_pam_jmp;
+
+void
+gray_raise(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ _pam_vlog(LOG_ERR, fmt, ap);
+ va_end(ap);
+ longjmp(gray_pam_jmp, 1);
+}
+
+void *
+gray_malloc(size_t size)
+{
+ void *p = malloc(size);
+ if (!p)
+ gray_raise("Not enough memory");
+ return p;
+}
+
+void *
+gray_zalloc(size_t size)
+{
+ void *p = malloc(size);
+ if (!p)
+ gray_raise("Not enough memory");
+ memset(p, 0, size);
+ return p;
+}
+
+void *
+gray_realloc(void *ptr, size_t size)
+{
+ ptr = realloc(ptr, size);
+ if (!ptr)
+ gray_raise("Not enough memory");
+ return ptr;
+}
+
+
+void
+gray_pam_delete(char *x)
+{
+ PAM_OVERWRITE(x);
+ free(x);
+}
+
+void
+gray_cleanup_string(pam_handle_t *pamh, void *x, int error_status)
+{
+ gray_pam_delete(x);
+}
+
+void
+gray_cleanup_regex(pam_handle_t *pamh, void *x, int error_status)
+{
+ regfree((regex_t*)x);
+}
+
+void
+gray_make_str(pam_handle_t *pamh, const char *str, const char *name,
+ char **ret)
+{
+ int retval;
+ char *newstr = XSTRDUP(str);
+
+ retval = pam_set_data(pamh, name, (void *)newstr, gray_cleanup_string);
+ if (retval != PAM_SUCCESS) {
+ _pam_log(LOG_CRIT,
+ "can't keep data [%s]: %s",
+ name,
+ pam_strerror(pamh, retval));
+ gray_pam_delete(newstr);
+ } else {
+ *ret = newstr;
+ newstr = NULL;
+ }
+}
+
+
diff --git a/lib/slist.c b/lib/slist.c
new file mode 100644
index 0000000..6a4820b
--- /dev/null
+++ b/lib/slist.c
@@ -0,0 +1,244 @@
+/* This file is part of pam_modules.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ Written by Sergey Poznyakoff
+
+ GNU Radius is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ GNU Radius is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with GNU Radius; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA. */
+
+#include <graypam.h>
+
+#define GRAY_SLIST_BUCKET_SIZE 1024
+
+struct gray_slist_bucket {
+ struct gray_slist_bucket *next;
+ char *buf;
+ size_t level;
+ size_t size;
+};
+
+struct gray_slist {
+ struct gray_slist_bucket *head, *tail;
+ struct gray_slist_bucket *free;
+};
+
+static struct gray_slist_bucket *
+alloc_bucket(size_t size)
+{
+ struct gray_slist_bucket *p = gray_malloc(sizeof(*p) + size);
+ p->buf = (char*)(p + 1);
+ p->level = 0;
+ p->size = size;
+ p->next = NULL;
+ return p;
+}
+
+static void
+alloc_pool(gray_slist_t slist, size_t size)
+{
+ struct gray_slist_bucket *p = alloc_bucket(GRAY_SLIST_BUCKET_SIZE);
+ if (slist->tail)
+ slist->tail->next = p;
+ else
+ slist->head = p;
+ slist->tail = p;
+}
+
+static size_t
+copy_chars(gray_slist_t slist, const char *str, size_t n)
+{
+ size_t rest;
+
+
+ if (!slist->head || slist->tail->level == slist->tail->size)
+ alloc_pool(slist, GRAY_SLIST_BUCKET_SIZE);
+ rest = slist->tail->size - slist->tail->level;
+ if (n > rest)
+ n = rest;
+ memcpy(slist->tail->buf + slist->tail->level, str, n);
+ slist->tail->level += n;
+ return n;
+}
+
+gray_slist_t
+gray_slist_create()
+{
+ gray_slist_t slist = gray_