From 222d4ff80720206deeb8e7ee87831812628329af Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Thu, 13 Mar 2008 13:53:32 +0000 Subject: * 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 --- ChangeLog | 17 ++ Make.rules | 26 +++ Makefile.am | 5 +- NEWS | 14 +- common.c | 150 ------------- configure.ac | 5 +- doc/pam-modules.texi | 80 ++++++- lib/Makefile.am | 19 ++ lib/converse.c | 49 +++++ lib/graypam.h | 149 +++++++++++++ lib/log.c | 79 +++++++ lib/mem.c | 99 +++++++++ lib/slist.c | 244 +++++++++++++++++++++ lib/transform.c | 533 ++++++++++++++++++++++++++++++++++++++++++++++ pam_fshadow/Makefile.am | 15 +- pam_fshadow/pam_fshadow.c | 97 ++------- pam_log/Makefile.am | 15 +- pam_log/pam_log.c | 79 +++---- pam_regex/Makefile.am | 18 +- pam_regex/pam_regex.c | 150 +++++++------ pam_sql/Makefile.am | 3 +- pam_sql/pam_mysql.c | 15 +- pam_sql/pam_pgsql.c | 15 +- pam_sql/pam_sql.c | 79 +------ 24 files changed, 1475 insertions(+), 480 deletions(-) create mode 100644 Make.rules delete mode 100644 common.c create mode 100644 lib/Makefile.am create mode 100644 lib/converse.c create mode 100644 lib/graypam.h create mode 100644 lib/log.c create mode 100644 lib/mem.c create mode 100644 lib/slist.c create mode 100644 lib/transform.c diff --git a/ChangeLog b/ChangeLog index e2fb656..80ebb18 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2008-03-13 Sergey Poznyakoff + + * 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 * 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 . + +.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 . 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 -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 . */ - -#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 - -#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 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 @@ -181,7 +181,8 @@ else fi]) AC_OUTPUT(Makefile - doc/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 . + +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 . */ + +#include + +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 . */ + +#ifndef _graypam_h_ +#define _graypam_h_ + +#if defined(HAVE_CONFIG_H) +# include +#endif +#ifdef HAVE__PAM_ACONF_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef LINUX_PAM +#include +#endif /* LINUX_PAM */ +#include + +#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 + +#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; p; p = p->next) + size += p->level; + return size; +} + +size_t +gray_slist_coalesce(gray_slist_t slist) +{ + size_t size; + + if (slist->head && slist->head->next == NULL) + size = slist->head->level; + else { + size = gray_slist_size(slist); + struct gray_slist_bucket *bucket = alloc_bucket(size); + struct gray_slist_bucket *p; + + for (p = slist->head; p; ) { + struct gray_slist_bucket *next = p->next; + memcpy(bucket->buf + bucket->level, p->buf, p->level); + bucket->level += p->level; + free(p); + p = next; + } + slist->head = slist->tail = bucket; + } + return size; +} + +void * +gray_slist_head(gray_slist_t slist, size_t *psize) +{ + if (*psize) + *psize = slist->head ? slist->head->level : 0; + return slist->head ? slist->head->buf : NULL; +} + +void * +gray_slist_finish(gray_slist_t slist) +{ + gray_slist_coalesce(slist); + gray_slist_clear(slist); + return slist->free->buf; +} + + +#define to_num(c) \ + (isdigit(c) ? c - '0' : (isxdigit(c) ? toupper(c) - 'A' + 10 : 255 )) + +void +gray_slist_grow_backslash_num(gray_slist_t slist, char *text, char **pend, + int len, int base) +{ + int i; + int val = 0; + char *start = text; + + if (text[0] == '\\') { + text++; + if (base == 16) + text++; + } + + for (i = 0; i < len; i++) { + int n = (unsigned char)text[i]; + if (n > 127 || (n = to_num(n)) >= base) + break; + val = val*base + n; + } + + if (i == 0) { + gray_slist_append(slist, start, 1); + if (pend) + *pend = start + 1; + } else { + gray_slist_append_char(slist, val); + if (pend) + *pend = text + i; + } +} + +int +gray_decode_backslash(int c) +{ + static char transtab[] = "a\ab\bf\fn\nr\rt\t"; + char *p; + + for (p = transtab; *p; p += 2) { + if (*p == c) + return p[1]; + } + return c; +} + +void +gray_slist_grow_backslash(gray_slist_t slist, char *text, char **endp) +{ + if (text[1] == '\\' || (unsigned char)text[1] > 127) { + gray_slist_append_char(slist, text[1]); + text += 2; + } else if (isdigit(text[1])) + gray_slist_grow_backslash_num(slist, text, &text, 3, 8); + else if (text[1] == 'x' || text[1] == 'X') + gray_slist_grow_backslash_num(slist, text, &text, 2, 16); + else { + int c = gray_decode_backslash(text[1]); + gray_slist_append_char(slist, c); + text += 2; + } + + *endp = text; +} + diff --git a/lib/transform.c b/lib/transform.c new file mode 100644 index 0000000..17fc651 --- /dev/null +++ b/lib/transform.c @@ -0,0 +1,533 @@ +/* This file is part of pam_modules. + Copyright (C) 2006, 2007, 2008 Sergey Poznyakoff. + (using my implementation for the GNU tar). + + 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include + +enum transform_type + { + transform_first, + transform_global + }; + +enum replace_segm_type + { + segm_literal, /* Literal segment */ + segm_backref, /* Back-reference segment */ + segm_case_ctl /* Case control segment (GNU extension) */ + }; + +enum case_ctl_type + { + ctl_stop, /* Stop case conversion */ + ctl_upcase_next,/* Turn the next character to uppercase */ + ctl_locase_next,/* Turn the next character to lowercase */ + ctl_upcase, /* Turn the replacement to uppercase until ctl_stop */ + ctl_locase /* Turn the replacement to lowercase until ctl_stop */ + }; + +struct replace_segm +{ + struct replace_segm *next; + enum replace_segm_type type; + union + { + struct + { + char *ptr; + size_t size; + } literal; /* type == segm_literal */ + size_t ref; /* type == segm_backref */ + enum case_ctl_type ctl; /* type == segm_case_ctl */ + } v; +}; + +struct transform +{ + struct transform *next; + enum transform_type transform_type; + unsigned match_number; + regex_t regex; + /* Compiled replacement expression */ + struct replace_segm *repl_head, *repl_tail; + size_t segm_count; /* Number of elements in the above list */ +}; + + +static struct transform *transform_head, *transform_tail; + +static struct transform * +new_transform () +{ + struct transform *p = gray_zalloc (sizeof *p); + if (transform_tail) + transform_tail->next = p; + else + transform_head = p; + transform_tail = p; + return p; +} + +static struct replace_segm * +add_segment (struct transform *tf) +{ + struct replace_segm *segm = gray_malloc (sizeof *segm); + segm->next = NULL; + if (tf->repl_tail) + tf->repl_tail->next = segm; + else + tf->repl_head = segm; + tf->repl_tail = segm; + tf->segm_count++; + return segm; +} + +static void +add_literal_segment (struct transform *tf, char *str, char *end) +{ + size_t len = end - str; + if (len) + { + struct replace_segm *segm = add_segment (tf); + segm->type = segm_literal; + segm->v.literal.ptr = gray_malloc (len + 1); + memcpy (segm->v.literal.ptr, str, len); + segm->v.literal.ptr[len] = 0; + segm->v.literal.size = len; + } +} + +static void +add_char_segment (struct transform *tf, int chr) +{ + struct replace_segm *segm = add_segment (tf); + segm->type = segm_literal; + segm->v.literal.ptr = gray_malloc (2); + segm->v.literal.ptr[0] = chr; + segm->v.literal.ptr[1] = 0; + segm->v.literal.size = 1; +} + +static void +add_backref_segment (struct transform *tf, size_t ref) +{ + struct replace_segm *segm = add_segment (tf); + segm->type = segm_backref; + segm->v.ref = ref; +} + +static void +add_case_ctl_segment (struct transform *tf, enum case_ctl_type ctl) +{ + struct replace_segm *segm = add_segment (tf); + segm->type = segm_case_ctl; + segm->v.ctl = ctl; +} + +static const char * +parse_transform_expr (const char *expr) +{ + int delim; + int i, j, rc; + char *str, *beg, *cur; + const char *p; + int cflags = 0; + struct transform *tf = new_transform (); + + if (expr[0] != 's') + gray_raise ("Invalid transform expression"); + + delim = expr[1]; + + /* Scan regular expression */ + for (i = 2; expr[i] && expr[i] != delim; i++) + if (expr[i] == '\\' && expr[i+1]) + i++; + + if (expr[i] != delim) + gray_raise ("Invalid transform expression"); + + /* Scan replacement expression */ + for (j = i + 1; expr[j] && expr[j] != delim; j++) + if (expr[j] == '\\' && expr[j+1]) + j++; + + if (expr[j] != delim) + gray_raise ("Invalid transform expression"); + + /* Check flags */ + tf->transform_type = transform_first; + for (p = expr + j + 1; *p && *p != ';'; p++) + switch (*p) + { + case 'g': + tf->transform_type = transform_global; + break; + + case 'i': + cflags |= REG_ICASE; + break; + + case 'x': + cflags |= REG_EXTENDED; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + tf->match_number = strtoul (p, (char**) &p, 0); + p--; + break; + + default: + gray_raise("Unknown flag in transform expression: %c", *p); + } + + if (*p == ';') + p++; + + /* Extract and compile regex */ + str = gray_malloc (i - 1); + memcpy (str, expr + 2, i - 2); + str[i - 2] = 0; + + rc = regcomp (&tf->regex, str, cflags); + + if (rc) + { + char errbuf[512]; + regerror (rc, &tf->regex, errbuf, sizeof (errbuf)); + gray_raise("Invalid transform expression: %s", errbuf); + } + + if (str[0] == '^' || str[strlen (str) - 1] == '$') + tf->transform_type = transform_first; + + free (str); + + /* Extract and compile replacement expr */ + i++; + str = gray_malloc (j - i + 1); + memcpy (str, expr + i, j - i); + str[j - i] = 0; + + for (cur = beg = str; *cur;) + { + if (*cur == '\\') + { + size_t n; + + add_literal_segment (tf, beg, cur); + switch (*++cur) + { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = strtoul (cur, &cur, 10); + if (n > tf->regex.re_nsub) + gray_raise ("Invalid transform replacement: " + "back reference out of range"); + add_backref_segment (tf, n); + break; + + case '\\': + add_char_segment (tf, '\\'); + cur++; + break; + + case 'a': + add_char_segment (tf, '\a'); + cur++; + break; + + case 'b': + add_char_segment (tf, '\b'); + cur++; + break; + + case 'f': + add_char_segment (tf, '\f'); + cur++; + break; + + case 'n': + add_char_segment (tf, '\n'); + cur++; + break; + + case 'r': + add_char_segment (tf, '\r'); + cur++; + break; + + case 't': + add_char_segment (tf, '\t'); + cur++; + break; + + case 'v': + add_char_segment (tf, '\v'); + cur++; + break; + + case '&': + add_char_segment (tf, '&'); + cur++; + break; + + case 'L': + /* Turn the replacement to lowercase until a `\U' or `\E' + is found, */ + add_case_ctl_segment (tf, ctl_locase); + cur++; + break; + + case 'l': + /* Turn the next character to lowercase, */ + add_case_ctl_segment (tf, ctl_locase_next); + cur++; + break; + + case 'U': + /* Turn the replacement to uppercase until a `\L' or `\E' + is found, */ + add_case_ctl_segment (tf, ctl_upcase); + cur++; + break; + + case 'u': + /* Turn the next character to uppercase, */ + add_case_ctl_segment (tf, ctl_upcase_next); + cur++; + break; + + case 'E': + /* Stop case conversion started by `\L' or `\U'. */ + add_case_ctl_segment (tf, ctl_stop); + cur++; + break; + + default: + /* Try to be nice */ + { + char buf[2]; + buf[0] = '\\'; + buf[1] = *cur; + add_literal_segment (tf, buf, buf + 2); + } + cur++; + break; + } + beg = cur; + } + else if (*cur == '&') + { + add_literal_segment (tf, beg, cur); + add_backref_segment (tf, 0); + beg = ++cur; + } + else + cur++; + } + add_literal_segment (tf, beg, cur); + + return p; +} + +void +gray_set_transform_expr (const char *expr) +{ + while (*expr) + expr = parse_transform_expr (expr); +} + +/* Run case conversion specified by CASE_CTL on array PTR of SIZE + characters. Returns pointer to statically allocated storage. */ +static char * +run_case_conv (enum case_ctl_type case_ctl, char *ptr, size_t size) +{ + static char *case_ctl_buffer; + static size_t case_ctl_bufsize; + char *p; + + if (case_ctl_bufsize < size) + { + case_ctl_bufsize = size; + case_ctl_buffer = gray_realloc (case_ctl_buffer, case_ctl_bufsize); + } + memcpy (case_ctl_buffer, ptr, size); + switch (case_ctl) + { + case ctl_upcase_next: + case_ctl_buffer[0] = toupper (case_ctl_buffer[0]); + break; + + case ctl_locase_next: + case_ctl_buffer[0] = tolower (case_ctl_buffer[0]); + break; + + case ctl_upcase: + for (p = case_ctl_buffer; p < case_ctl_buffer + size; p++) + *p = toupper (*p); + break; + + case ctl_locase: + for (p = case_ctl_buffer; p < case_ctl_buffer + size; p++) + *p = tolower (*p); + break; + + case ctl_stop: + break; + } + return case_ctl_buffer; +} + + +void +_single_transform_name_to_slist (struct transform *tf, gray_slist_t slist, + char *input) +{ + regmatch_t *rmp; + int rc; + size_t nmatches = 0; + enum case_ctl_type case_ctl = ctl_stop, /* Current case conversion op */ + save_ctl = ctl_stop; /* Saved case_ctl for \u and \l */ + + /* Reset case conversion after a single-char operation */ +#define CASE_CTL_RESET() if (case_ctl == ctl_upcase_next \ + || case_ctl == ctl_locase_next) \ + { \ + case_ctl = save_ctl; \ + save_ctl = ctl_stop; \ + } + + rmp = gray_malloc ((tf->regex.re_nsub + 1) * sizeof (*rmp)); + + while (*input) + { + size_t disp; + char *ptr; + + rc = regexec (&tf->regex, input, tf->regex.re_nsub + 1, rmp, 0); + + if (rc == 0) + { + struct replace_segm *segm; + + disp = rmp[0].rm_eo; + + if (rmp[0].rm_so) + gray_slist_append (slist, input, rmp[0].rm_so); + + nmatches++; + if (tf->match_number && nmatches < tf->match_number) + { + gray_slist_append (slist, input, disp); + input += disp; + continue; + } + + for (segm = tf->repl_head; segm; segm = segm->next) + { + switch (segm->type) + { + case segm_literal: /* Literal segment */ + if (case_ctl == ctl_stop) + ptr = segm->v.literal.ptr; + else + { + ptr = run_case_conv (case_ctl, + segm->v.literal.ptr, + segm->v.literal.size); + CASE_CTL_RESET(); + } + gray_slist_append (slist, ptr, segm->v.literal.size); + break; + + case segm_backref: /* Back-reference segment */ + if (rmp[segm->v.ref].rm_so != -1 + && rmp[segm->v.ref].rm_eo != -1) + { + size_t size = rmp[segm->v.ref].rm_eo + - rmp[segm->v.ref].rm_so; + ptr = input + rmp[segm->v.ref].rm_so; + if (case_ctl != ctl_stop) + { + ptr = run_case_conv (case_ctl, ptr, size); + CASE_CTL_RESET(); + } + + gray_slist_append (slist, ptr, size); + } + break; + + case segm_case_ctl: + switch (segm->v.ctl) + { + case ctl_upcase_next: + case ctl_locase_next: + switch (save_ctl) + { + case ctl_stop: + case ctl_upcase: + case ctl_locase: + save_ctl = case_ctl; + default: + break; + } + /*FALL THROUGH*/ + + case ctl_upcase: + case ctl_locase: + case ctl_stop: + case_ctl = segm->v.ctl; + } + } + } + } + else + { + disp = strlen (input); + gray_slist_append (slist, input, disp); + } + + input += disp; + + if (tf->transform_type == transform_first) + { + gray_slist_append (slist, input, strlen (input)); + break; + } + } + + gray_slist_append_char (slist, 0); + free (rmp); +} + +int +gray_transform_name_to_slist (gray_slist_t slist, char *input, char **output) +{ + struct transform *tf; + + for (tf = transform_head; tf; tf = tf->next) + { + _single_transform_name_to_slist (tf, slist, input); + input = gray_slist_finish (slist); + } + *output = input; + return transform_head != NULL; +} + + diff --git a/pam_fshadow/Makefile.am b/pam_fshadow/Makefile.am index 10849cb..f996406 100644 --- a/pam_fshadow/Makefile.am +++ b/pam_fshadow/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (C) 2001, 2006, 2007 Sergey Poznyakoff +# Copyright (C) 2001, 2006, 2007, 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 @@ -17,18 +17,13 @@ pamdir=@PAMDIR@ pam_PROGRAMS = pam_fshadow.la AM_INSTALLCHECK_STD_OPTIONS_EXEMPT = pam_fshadow.la pam_fshadow_la_SOURCES = pam_fshadow.c -pam_fshadow_la_LDADD = -lpam @LIBS@ +LDADD = -lpam @LIBS@ ../lib/libgraypam.la AM_LDFLAGS = -version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@ AM_CPPFLAGS=-DMODULE_NAME=\"pam_fshadow\" -DSYSCONFDIR=\"${sysconfdir}\" INCLUDES=@PAM_COMMON_INCLUDES@ NORMAL_UNINSTALL = -rm -f $(DESTDIR)$(pamdir)/pam_fshadow.a $(DESTDIR)$(pamdir)/pam_fshadow.so.@VI_CURRENT@.@VI_REVISION@.@VI_AGE@ -pam_fshadow.lo: $(srcdir)/pam_fshadow.c - $(LIBTOOL) --mode=compile $(CC) -c -DHAVE_CONFIG_H \ - $(CFLAGS) $(AM_CFLAGS) $(INCLUDES) $(CPPFLAGS) $(AM_CPPFLAGS) $< +include $(top_srcdir)/Make.rules -pam_fshadow.la$(EXEEXT): pam_fshadow.lo - $(LIBTOOL) --mode=link $(CC) -module -export-dynamic \ - $(AM_LDFLAGS) \ - -o $@ $< $(pam_fshadow_la_LDADD) $(AM_LDADD) $(LDADD) \ - -rpath $(pamdir) +pam_fshadow.lo: pam_fshadow.c +pam_fshadow.la: pam_fshadow.lo diff --git a/pam_fshadow/pam_fshadow.c b/pam_fshadow/pam_fshadow.c index 9e7ab68..dea6357 100644 --- a/pam_fshadow/pam_fshadow.c +++ b/pam_fshadow/pam_fshadow.c @@ -1,5 +1,5 @@ /* This file is part of pam-modules. - * Copyright (C) 2001, 2005, 2007 Sergey Poznyakoff + * Copyright (C) 2001, 2005, 2007, 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 @@ -17,34 +17,22 @@ /* pam_fshadow */ -#if defined(HAVE_CONFIG_H) -# include -#endif - -#include - -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include #include #include -#include + +#if defined(HAVE_CRYPT_H) +# include +#else +extern char *crypt(const char *, const char *); +#endif #define PAM_SM_AUTH #define PAM_SM_ACCOUNT #include -#include - char *sysconfdir = SYSCONFDIR; static int cntl_flags = 0; @@ -53,20 +41,17 @@ const char *regex_str = NULL; static int username_index = 1; static int domain_index = 2; -#define CNTL_DEBUG 0x0001 -#define CNTL_AUTHTOK 0x0002 -#define CNTL_NOPASSWD 0x0004 -#define CNTL_REGEX 0x0008 - -#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 CNTL_AUTHTOK 0x0010 +#define CNTL_NOPASSWD 0x0020 +#define CNTL_REGEX 0x0040 static int _pam_parse(pam_handle_t *pamh, int argc, const char **argv) { int regex_flags = 0; int retval = PAM_SUCCESS; + + gray_log_init(0, MODULE_NAME, LOG_AUTHPRIV); /* step through arguments */ for (cntl_flags = 0; argc-- > 0; ++argv) { @@ -81,7 +66,7 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv) else CNTL_SET_DEBUG_LEV(cntl_flags, 1); } else if (!strncmp(*argv, "waitdebug", 9)) - WAITDEBUG(*argv + 9); + WAITDEBUG(*argv + 9); else if (!strcmp(*argv,"use_authtok")) cntl_flags |= CNTL_AUTHTOK; else if (!strncmp(*argv, "sysconfdir=", 11)) @@ -132,7 +117,7 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv) } else { cntl_flags |= CNTL_REGEX; rc = pam_set_data(pamh, "REGEX", &rexp, - _cleanup_regex); + gray_cleanup_regex); if (rc != PAM_SUCCESS) { _pam_log(LOG_NOTICE, @@ -146,44 +131,6 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv) return retval; } -static int -converse(pam_handle_t *pamh, - int nargs, - struct pam_message **message, - struct pam_response **response) -{ - int retval; - struct pam_conv *conv; - - DEBUG(100,("enter converse")); - - retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv); - DEBUG(10,("pam_get_item(PAM_CONV): %d", retval)); - if (retval == PAM_SUCCESS) { - - retval = conv->conv(nargs, - (const struct pam_message **) message, - response, - conv->appdata_ptr); - - DEBUG(10, ("app conversation returned %d", retval)); - - 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)); - } - - DEBUG(100,("exit converse: %d", retval)); - - return retval; /* propagate error status */ -} - static int _pam_get_password(pam_handle_t *pamh, char **password, const char *prompt) { @@ -229,11 +176,11 @@ _pam_get_password(pam_handle_t *pamh, char **password, const char *prompt) /* run conversation */ resp = NULL; token = NULL; - retval = converse(pamh, i, pmsg, &resp); + retval = gray_converse(pamh, i, pmsg, &resp); if (resp != NULL) { if (retval == PAM_SUCCESS) { /* a good conversation */ - token = XSTRDUP(resp[i - replies].resp); + token = XSTRDUP(resp[i - replies].resp); DEBUG(10,("app returned [%s]", token)); PAM_DROP_REPLY(resp, 1); } else { @@ -253,12 +200,12 @@ _pam_get_password(pam_handle_t *pamh, char **password, const char *prompt) */ retval = pam_set_data(pamh, "password", (void *)token, - _cleanup_string); + gray_cleanup_string); if (retval != PAM_SUCCESS) { _pam_log(LOG_CRIT, "can't keep password: %s", pam_strerror(pamh, retval)); - _pam_delete(token); + gray_pam_delete(token); } else { *password = token; token = NULL; /* break link to password */ @@ -397,13 +344,13 @@ copy_backref (pam_handle_t *pamh, const char *name, _pam_log(LOG_CRIT, "not enough memory"); return PAM_SYSTEM_ERR; } - rc = pam_set_data(pamh, name, (void *)str, _cleanup_string); + rc = pam_set_data(pamh, name, (void *)str, gray_cleanup_string); if (rc != PAM_SUCCESS) { _pam_log(LOG_CRIT, "can't keep data [%s]: %s", name, pam_strerror(pamh, rc)); - _pam_delete(str); + gray_pam_delete(str); } else { if (size != 0) memcpy(str, buf + rmatch[index].rm_so, size); @@ -453,7 +400,7 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, return rc; confdir = mkfilename(sysconfdir, domain); pam_set_data(pamh, "CONFDIR", - (void *)confdir, _cleanup_string); + (void *)confdir, gray_cleanup_string); } else { _pam_log(LOG_DEBUG, "user name `%s' does not match regular " diff --git a/pam_log/Makefile.am b/pam_log/Makefile.am index 886baea..80bb0bd 100644 --- a/pam_log/Makefile.am +++ b/pam_log/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (C) 2006 Sergey Poznyakoff +# Copyright (C) 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 @@ -17,18 +17,13 @@ pamdir=@PAMDIR@ pam_PROGRAMS = pam_log.la AM_INSTALLCHECK_STD_OPTIONS_EXEMPT = pam_log.la pam_log_la_SOURCES = pam_log.c -pam_log_la_LDADD = -lpam +LDADD = -lpam ../lib/libgraypam.la AM_LDFLAGS = -version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@ AM_CPPFLAGS=-DMODULE_NAME=\"pam_log\" -DSYSCONFDIR=\"${sysconfdir}\" INCLUDES=@PAM_COMMON_INCLUDES@ NORMAL_UNINSTALL = -rm -f $(DESTDIR)$(pamdir)/pam_log.a $(DESTDIR)$(pamdir)/pam_log.so.@VI_CURRENT@.@VI_REVISION@.@VI_AGE@ -pam_log.lo: $(srcdir)/pam_log.c - $(LIBTOOL) --mode=compile $(CC) -c -DHAVE_CONFIG_H \ - $(CFLAGS) $(AM_CFLAGS) $(INCLUDES) $(CPPFLAGS) $(AM_CPPFLAGS) $< +include $(top_srcdir)/Make.rules -pam_log.la$(EXEEXT): pam_log.lo - $(LIBTOOL) --mode=link $(CC) -module -export-dynamic \ - $(AM_LDFLAGS) \ - -o $@ $< $(pam_log_la_LDADD) $(AM_LDADD) $(LDADD)\ - -rpath $(pamdir) +pam_log.lo: pam_log.c +pam_log.la: pam_log.lo diff --git a/pam_log/pam_log.c b/pam_log/pam_log.c index bc39be1..0b81ee5 100644 --- a/pam_log/pam_log.c +++ b/pam_log/pam_log.c @@ -1,5 +1,5 @@ /* This file is part of pam-modules. - Copyright (C) 2006, 2007 Sergey Poznyakoff + Copyright (C) 2006, 2007, 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 @@ -14,46 +14,17 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#if defined(HAVE_CONFIG_H) -# include -#endif -#ifdef HAVE__PAM_ACONF_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#define obstack_chunk_alloc malloc -#define obstack_chunk_free free -#include - -#define PAM_SM_AUTH -#define PAM_SM_PASSWORD -#include - -#include +#include /* 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)) - static int cntl_flags; static int xargc; static const char **xargv; static int priority = LOG_INFO; - -#define DEBUG(m,c) if (CNTL_DEBUG_LEV()>=(m)) _pam_debug c -#define AUDIT(c) if (cntl_flags&CNTL_AUDIT) _pam_debug c +static int facility = LOG_AUTHPRIV; +static const char *syslog_tag =MODULE_NAME; struct keyword { char *name; @@ -137,7 +108,8 @@ static void _pam_parse(pam_handle_t *pamh, int argc, const char **argv) { int ctrl = 0; - + int dont_open = 0; + /* Collect generic arguments */ for (; argc > 0; argv++, argc--) { if (!strncmp(*argv, "-debug", 6)) { @@ -155,7 +127,7 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv) else if (!strncmp(*argv, "-pri=", 5)) parse_priority(*argv + 5); else if (!strcmp(*argv, "-no-open")) - syslog_dont_open = 1; + dont_open = 1; else if (!strcmp(*argv, "--")) break; else if (**argv == '-') @@ -170,6 +142,8 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv) xargv = argv; cntl_flags = ctrl; + + gray_log_init(dont_open, syslog_tag, facility); } static struct keyword vartab[] = { @@ -214,7 +188,7 @@ repl_tok(const char *str, const char ** pret, size_t *plen) } static int -get_variable(pam_handle_t *pamh, const char *str, struct obstack *stk, +get_variable(pam_handle_t *pamh, const char *str, gray_slist_t slist, const char **endp) { const char *name; @@ -277,36 +251,37 @@ get_variable(pam_handle_t *pamh, const char *str, struct obstack *stk, } else vallen = strlen(val); - obstack_grow(stk, val, vallen); + gray_slist_append(slist, val, vallen); *endp = end; return 0; } static void -expand_string(pam_handle_t *pamh, struct obstack *stk) +expand_string(pam_handle_t *pamh, gray_slist_t slist) { int i; for (i = 0; i < xargc; i++) { DEBUG(2,("%s: %d %s", __FUNCTION__, i, xargv[i])); if (i > 0) - obstack_1grow(stk, ' '); + gray_slist_append_char(slist, ' '); if (strchr(xargv[i], '$') == 0) - obstack_grow(stk, xargv[i], strlen(xargv[i])); + gray_slist_append(slist, xargv[i], strlen(xargv[i])); else { const char *p; for (p = xargv[i]; *p; p++) { if (*p == '\\') { p++; - obstack_1grow(stk, *p); + gray_slist_append_char(slist, *p); } else if (*p == '$') { - if (get_variable(pamh, p, stk, &p)) - obstack_1grow(stk, *p); + if (get_variable(pamh, p, slist, &p)) + gray_slist_append_char(slist, + *p); else p--; } else - obstack_1grow(stk, *p); + gray_slist_append_char(slist, *p); } } } @@ -316,19 +291,19 @@ static int echo(pam_handle_t *pamh, const char *prefix, int argc, const char **argv) { char *str; - struct obstack stk; + gray_slist_t slist; _pam_parse(pamh, argc, argv); - obstack_init(&stk); + slist = gray_slist_create(); if (prefix) { - obstack_grow(&stk, prefix, strlen(prefix)); - obstack_grow(&stk, ": ", 2); + gray_slist_append(slist, prefix, strlen(prefix)); + gray_slist_append(slist, ": ", 2); } - expand_string(pamh, &stk); - obstack_1grow(&stk, 0); - str = obstack_finish(&stk); + expand_string(pamh, slist); + gray_slist_append_char(slist, 0); + str = gray_slist_finish(slist); _pam_log(priority, "%s", str); - obstack_free(&stk, NULL); + gray_slist_free(&slist); return PAM_IGNORE; } diff --git a/pam_regex/Makefile.am b/pam_regex/Makefile.am index 798b54d..a29daec 100644 --- a/pam_regex/Makefile.am +++ b/pam_regex/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 @@ -16,19 +16,15 @@ pamdir=@PAMDIR@ pam_PROGRAMS = pam_regex.la pam_regex_la_SOURCES = pam_regex.c +pam_regex_la_LDADD = ../lib/libgraypam.la AM_INSTALLCHECK_STD_OPTIONS_EXEMPT = pam_regex.la -pam_regex_la_LDADD = -lpam +LDADD = -lpam ../lib/libgraypam.la AM_LDFLAGS = -version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@ AM_CPPFLAGS=-DMODULE_NAME=\"pam_regex\" -DSYSCONFDIR=\"${sysconfdir}\" -INCLUDES=@PAM_COMMON_INCLUDES@ +INCLUDES=-I. @PAM_COMMON_INCLUDES@ NORMAL_UNINSTALL = -rm -f $(DESTDIR)$(pamdir)/pam_regex.a $(DESTDIR)$(pamdir)/pam_regex.so.@VI_CURRENT@.@VI_REVISION@.@VI_AGE@ -pam_regex.lo: $(srcdir)/pam_regex.c - $(LIBTOOL) --mode=compile $(CC) -c -DHAVE_CONFIG_H \ - $(CFLAGS) $(AM_CFLAGS) $(INCLUDES) $(CPPFLAGS) $(AM_CPPFLAGS) $< +include $(top_srcdir)/Make.rules -pam_regex.la$(EXEEXT): pam_regex.lo - $(LIBTOOL) --mode=link $(CC) -module -export-dynamic \ - $(AM_LDFLAGS) \ - -o $@ $< $(pam_regex_la_LDADD) $(AM_LDADD) $(LDADD)\ - -rpath $(pamdir) +pam_regex.lo: pam_regex.c +pam_regex.la: pam_regex.lo diff --git a/pam_regex/pam_regex.c b/pam_regex/pam_regex.c index 4d0eb3c..8529917 100644 --- a/pam_regex/pam_regex.c +++ b/pam_regex/pam_regex.c @@ -1,5 +1,5 @@ /* This file is part of pam-modules. - Copyright (C) 2001, 2006, 2007 Sergey Poznyakoff + Copyright (C) 2001, 2006, 2007, 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 @@ -14,9 +14,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#if defined(HAVE_CONFIG_H) -# include -#endif #ifdef HAVE__PAM_ACONF_H #include #endif @@ -31,6 +28,8 @@ #include #include +#include "graypam.h" + /* indicate the following groups are defined */ #define PAM_SM_AUTH @@ -39,31 +38,26 @@ #endif /* LINUX_PAM */ #include -#include - -#define CNTL_DEBUG 0x0001 -#define CNTL_AUDIT 0x0002 -#define CNTL_AUTHTOK 0x0004 - -#define CNTL_SENSE_DENY 0x0010 -#define CNTL_REGEX_FLAGS 0x0020 +#define CNTL_AUTHTOK 0x0010 +#define CNTL_REGEX_FLAGS 0x0012 -#define CNTL_DEBUG_LEV() (cntl_flags>>16) -#define CNTL_SET_DEBUG_LEV(cntl,n) (cntl |= ((n)<<16)) +#define SENSE_ALLOW 0 +#define SENSE_DENY 1 +static int sense; static int cntl_flags; static const char *regex = NULL; static int regex_flags = REG_NOSUB; -static const char *user_name = NULL; - -#define DEBUG(m,c) if (CNTL_DEBUG_LEV()>=(m)) _pam_debug c -#define AUDIT(c) if (cntl_flags&CNTL_AUDIT) _pam_debug c +static const char *transform = NULL; +static const char *user_name; static void _pam_parse(pam_handle_t *pamh, int argc, const char **argv) { int ctrl = 0; + gray_log_init(0, MODULE_NAME, LOG_AUTHPRIV); + /* step through arguments */ for (; argc-- > 0; ++argv) { @@ -83,11 +77,17 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv) ctrl |= CNTL_AUTHTOK; else if (!strncmp(*argv, "sense=", 6)) { if (strcmp(*argv + 6, "deny") == 0) - ctrl |= CNTL_SENSE_DENY; - else if (strcmp(*argv + 6, "allow")) + sense = SENSE_DENY; + else if (strcmp(*argv + 6, "allow") == 0) + sense = SENSE_ALLOW; + else _pam_log(LOG_ERR,"unknown sense value: %s", *argv + 6); - } else if (!strncmp(*argv, "regex=", 6)) + } else if (!strncmp(*argv, "transform=", 10)) + transform = *argv + 10; + else if (!strncmp(*argv, "user=",5)) + user_name = *argv + 5; + else if (!strncmp(*argv, "regex=", 6)) regex = *argv + 6; else if (!strcmp(*argv, "extended")) { regex_flags |= REG_EXTENDED; @@ -102,8 +102,6 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv) } else if (!strcmp(*argv, "case")) { regex_flags &= ~REG_ICASE; ctrl |= CNTL_REGEX_FLAGS; - } else if (!strncmp(*argv, "user=",5)) { - user_name = *argv + 5; } else { _pam_log(LOG_ERR, "unknown option: %s", *argv); @@ -111,7 +109,9 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv) } if (!regex) _pam_log(LOG_ERR, "regex not specified"); - if (!ctrl & CNTL_REGEX_FLAGS) + if (user_name && transform) + _pam_log(LOG_ERR, "Both `user' and `transform' are given"); + if (!(ctrl & CNTL_REGEX_FLAGS)) regex_flags |= REG_EXTENDED; cntl_flags = ctrl; } @@ -123,7 +123,7 @@ _pam_parse(pam_handle_t *pamh, int argc, const char **argv) /* Fun starts here :) - * pam_sm_authenticate() performs RADIUS authentication + * pam_sm_authenticate() performs authentication * */ @@ -133,56 +133,80 @@ pam_sm_authenticate(pam_handle_t *pamh, int argc, const char **argv) { - int retval; + int retval, rc; char *name; regex_t rx; - + regmatch_t rmatch[2]; + _pam_parse(pamh, argc, argv); DEBUG(100,("enter pam_sm_authenticate")); if (!regex) return PAM_AUTHINFO_UNAVAIL; - - for (;;) { - - /* - * get username - */ - retval = pam_get_user(pamh, (const char**)&name, "login: "); - if (retval == PAM_SUCCESS) { - DEBUG(10, ("username [%s] obtained", name)); - } else { - _pam_log(LOG_NOTICE, "can't get username"); - break; - } - if (regcomp(&rx, regex, regex_flags)) { - _pam_log(LOG_NOTICE, "can't compile regex: %s", regex); - retval = PAM_AUTHINFO_UNAVAIL; - break; - } + gray_pam_init(PAM_AUTHINFO_UNAVAIL); - retval = regexec(&rx, name, 0, NULL, 0); - if (retval) { - DEBUG(1,("%s does not match %s",name,regex)); - } - if (cntl_flags & CNTL_SENSE_DENY) - retval = !retval; - if (retval) { - _pam_log(LOG_NOTICE, "rejecting %s", name); - retval = PAM_AUTH_ERR; - } else { - _pam_log(LOG_NOTICE, "allowing %s", name); - if (user_name) { - retval = pam_set_item(pamh, PAM_USER, - strdup(user_name)); - DEBUG(100,("user name=%s, status=%d", - user_name,retval)); + /* + * get username + */ + retval = pam_get_user(pamh, (const char**)&name, "login: "); + if (retval == PAM_SUCCESS) { + DEBUG(10, ("username [%s] obtained", name)); + } else { + _pam_log(LOG_NOTICE, "can't get username"); + return PAM_AUTHINFO_UNAVAIL; + } + + if (transform) { + char *newname; + gray_slist_t slist; + + gray_set_transform_expr(transform); + slist = gray_slist_create(); + gray_transform_name_to_slist(slist, name, &newname); + DEBUG(100,("new name: %s", newname)); + MAKE_STR(pamh, newname, name); + pam_set_item(pamh, PAM_AUTHTOK, name); + } + + if (regex) { + for (;;) { + + if (rc = regcomp(&rx, regex, regex_flags)) { + char errbuf[512]; + regerror (rc, &rx, errbuf, sizeof (errbuf)); + _pam_log(LOG_ERR, "can't compile regex: %s", + errbuf); + retval = PAM_AUTHINFO_UNAVAIL; + break; + } + + retval = regexec(&rx, name, 2, rmatch, 0); + if (retval) { + DEBUG(1,("%s does not match %s",name,regex)); } - retval = PAM_SUCCESS; + + switch (sense) { + case SENSE_ALLOW: + break; + + case SENSE_DENY: + retval = !retval; + break; + + } + + if (retval != PAM_