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.ac3
-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.c93
-rw-r--r--pam_log/Makefile.am15
-rw-r--r--pam_log/pam_log.c77
-rw-r--r--pam_regex/Makefile.am18
-rw-r--r--pam_regex/pam_regex.c106
-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, 1449 insertions, 454 deletions
diff --git a/ChangeLog b/ChangeLog
index e2fb656..80ebb18 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+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,
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,4 +1,4 @@
-# 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
@@ -14,5 +14,4 @@
# 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,12 +1,16 @@
-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
@@ -37,7 +41,7 @@ Version 0.1
=========================================================================
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
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
@@ -26,7 +26,7 @@ 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
@@ -182,6 +182,7 @@ fi])
AC_OUTPUT(Makefile
doc/Makefile
+ lib/Makefile
pam_fshadow/Makefile
pam_regex/Makefile
pam_log/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
@@ -271,9 +271,9 @@ for the user name @samp{smith} in the files
@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
@@ -305,6 +305,80 @@ options (see above).
@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
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_malloc(sizeof(*slist));
+ slist->head = slist->tail = slist->free = 0;
+ return slist;
+}
+
+void
+gray_slist_clear(gray_slist_t slist)
+{
+ if (slist->tail) {
+ slist->tail->next = slist->free;
+ slist->free = slist->head;
+ slist->head = slist->tail = NULL;
+ }
+}
+
+
+void
+gray_slist_free(gray_slist_t *slist)
+{
+ struct gray_slist_bucket *p;
+ if (*slist) {
+ gray_slist_clear(*slist);
+ for (p = (*slist)->free; p; ) {
+ struct gray_slist_bucket *next = p->next;
+ free(p);
+ p = next;
+ }
+ }
+ free(*slist);
+ *slist = NULL;
+}
+
+void
+gray_slist_append(gray_slist_t slist, const char *str, size_t n)
+{
+ const char *ptr = str;
+ while (n) {
+ size_t s = copy_chars(slist, ptr, n);
+ ptr += s;
+ n -= s;
+ }
+}
+
+void
+gray_slist_append_char(gray_slist_t slist, char c)
+{
+ gray_slist_append(slist, &c, 1);
+}
+
+size_t
+gray_slist_size(gray_slist_t slist)
+{
+ size_t size = 0;
+ struct gray_slist_bucket *p;
+ for (p = slist->head