mirror of
git://git.gnu.org.ua/pam-modules.git
synced 2025-04-29 01:49:53 +03:00
Revamp build system. Add pam_ldaphome module.
* configure.ac: Test for ldap. (AC_OUTPUT): Create pam_ldaphome/Makefile. * acinclude.m4 (PM_ENABLE): Declare PAM_COND_<item> conditional in addition to BUILD_PAM_<item> substitution variable. * Makefile.am (SUBDIRS): Include most modules via conditionally defined Makefile variables. * lib/graypam.h (gray_env): New struct. (gray_env_get,gray_env_free,gray_env_read) (gray_boolean_true_p): New protos. * lib/env.c: New file. * lib/Makefile.am (libgraypam_la_SOURCES): Add env.c * pam_fshadow/Makefile.am: Remove BUILD_PAM_FSHADOW substitution. * pam_regex/Makefile.am: Remove BUILD_PAM_REGEX substitution. * pam_sql/pam_sql.c (free_config, boolean_true_p) (read_config): Remove. Use gray_env_* functions instead. All uses updated. * pam_regex/pam_regex.c: Fix typo. * pam_ldaphome/Makefile.am: New file. git-svn-id: file:///svnroot/pam-modules/trunk@118 56984be4-0537-0410-a56c-fcb268c96130
This commit is contained in:
parent
993eff1366
commit
1a80b647d6
13 changed files with 1155 additions and 181 deletions
29
ChangeLog
29
ChangeLog
|
@ -1,3 +1,32 @@
|
||||||
|
2012-05-13 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||||
|
|
||||||
|
Revamp build system. Add pam_ldaphome module.
|
||||||
|
|
||||||
|
* configure.ac: Test for ldap.
|
||||||
|
(AC_OUTPUT): Create pam_ldaphome/Makefile.
|
||||||
|
* acinclude.m4 (PM_ENABLE): Declare PAM_COND_<item>
|
||||||
|
conditional in addition to BUILD_PAM_<item> substitution
|
||||||
|
variable.
|
||||||
|
* Makefile.am (SUBDIRS): Include most modules via
|
||||||
|
conditionally defined Makefile variables.
|
||||||
|
|
||||||
|
* lib/graypam.h (gray_env): New struct.
|
||||||
|
(gray_env_get,gray_env_free,gray_env_read)
|
||||||
|
(gray_boolean_true_p): New protos.
|
||||||
|
* lib/env.c: New file.
|
||||||
|
* lib/Makefile.am (libgraypam_la_SOURCES): Add env.c
|
||||||
|
|
||||||
|
* pam_fshadow/Makefile.am: Remove BUILD_PAM_FSHADOW
|
||||||
|
substitution.
|
||||||
|
* pam_regex/Makefile.am: Remove BUILD_PAM_REGEX
|
||||||
|
substitution.
|
||||||
|
* pam_sql/pam_sql.c (free_config, boolean_true_p)
|
||||||
|
(read_config): Remove. Use gray_env_* functions
|
||||||
|
instead. All uses updated.
|
||||||
|
* pam_regex/pam_regex.c: Fix typo.
|
||||||
|
|
||||||
|
* pam_ldaphome/Makefile.am: New file.
|
||||||
|
|
||||||
2011-09-29 Sergey Poznyakoff <gray@gnu.org.ua>
|
2011-09-29 Sergey Poznyakoff <gray@gnu.org.ua>
|
||||||
|
|
||||||
Allow installers to link modules with alternative crypt(3)
|
Allow installers to link modules with alternative crypt(3)
|
||||||
|
|
22
Makefile.am
22
Makefile.am
|
@ -14,4 +14,24 @@
|
||||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
AUTOMAKE_OPTIONS = gnits 1.8
|
AUTOMAKE_OPTIONS = gnits 1.8
|
||||||
SUBDIRS = doc lib pam_fshadow pam_regex pam_log pam_sql pamck
|
if PAM_COND_FSHADOW
|
||||||
|
FSHADOW_DIR=pam_fshadow
|
||||||
|
endif
|
||||||
|
if PAM_COND_REGEX
|
||||||
|
REGEX_DIR=pam_regex
|
||||||
|
endif
|
||||||
|
if PAM_COND_LOG
|
||||||
|
LOG_DIR=pam_regex
|
||||||
|
endif
|
||||||
|
if PAM_COND_LDAPHOME
|
||||||
|
LDAPHOME_DIR=pam_ldaphome
|
||||||
|
endif
|
||||||
|
SUBDIRS = \
|
||||||
|
doc\
|
||||||
|
lib\
|
||||||
|
$(FSHADOW_DIR)\
|
||||||
|
$(REGEX_DIR)\
|
||||||
|
$(LOG_DIR)\
|
||||||
|
pam_sql\
|
||||||
|
$(LDAPHOME_DIR)\
|
||||||
|
pamck
|
||||||
|
|
14
acinclude.m4
14
acinclude.m4
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (C) 2001, 2006, 2008-2011 Sergey Poznyakoff
|
# Copyright (C) 2001, 2006, 2008-2012 Sergey Poznyakoff
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,13 +18,17 @@ AC_DEFUN([PM_ENABLE],[
|
||||||
AC_HELP_STRING([--disable-$1], [Disable pam_$1]),
|
AC_HELP_STRING([--disable-$1], [Disable pam_$1]),
|
||||||
[if test $build_$1 = probe; then
|
[if test $build_$1 = probe; then
|
||||||
build_$1=$enableval
|
build_$1=$enableval
|
||||||
fi])
|
fi],
|
||||||
|
[build_$1=probe])
|
||||||
|
m4_pushdef([upmodname],translit($1, [a-z.-], [A-Z__]))
|
||||||
if test $build_$1 != no; then
|
if test $build_$1 != no; then
|
||||||
build_$1=yes
|
build_$1=yes
|
||||||
m4_pushdef([upmodname],[PAM_]translit($1, [a-z.-], [A-Z__]))
|
AC_SUBST([BUILD_PAM_]upmodname, ['$(]upmodname[)'])
|
||||||
AC_SUBST([BUILD_]upmodname, ['$(]upmodname[)'])
|
|
||||||
$2
|
$2
|
||||||
fi])
|
fi
|
||||||
|
AM_CONDITIONAL([PAM_COND_]upmodname, [test "$[]build_$1" = "yes"])
|
||||||
|
m4_popdef([upmodname])
|
||||||
|
])
|
||||||
|
|
||||||
dnl PM_FLUSHLEFT -- remove all whitespace at the beginning of lines
|
dnl PM_FLUSHLEFT -- remove all whitespace at the beginning of lines
|
||||||
dnl This is useful for c-code which may include cpp statements
|
dnl This is useful for c-code which may include cpp statements
|
||||||
|
|
20
configure.ac
20
configure.ac
|
@ -30,12 +30,6 @@ AC_SUBST(VI_CURRENT,1)
|
||||||
AC_SUBST(VI_REVISION,0)
|
AC_SUBST(VI_REVISION,0)
|
||||||
AC_SUBST(VI_AGE,0)
|
AC_SUBST(VI_AGE,0)
|
||||||
|
|
||||||
dnl Modules
|
|
||||||
build_fshadow=probe
|
|
||||||
build_regex=probe
|
|
||||||
build_log=probe
|
|
||||||
build_pgsql=probe
|
|
||||||
|
|
||||||
dnl Checks for programs.
|
dnl Checks for programs.
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
|
@ -153,6 +147,14 @@ AC_SUBST(MYSQLLIBS)
|
||||||
AC_SUBST(PGSQLLIBS)
|
AC_SUBST(PGSQLLIBS)
|
||||||
AC_SUBST(SQL_MODULES)
|
AC_SUBST(SQL_MODULES)
|
||||||
|
|
||||||
|
# LDAP support
|
||||||
|
PM_ENABLE(ldaphome)
|
||||||
|
if test $build_ldaphome = probe; then
|
||||||
|
AC_CHECK_LIB(ldap, ldap_bind,
|
||||||
|
[build_ldaphome=yes]
|
||||||
|
[build_ldaphome=no])
|
||||||
|
fi
|
||||||
|
|
||||||
## *****************
|
## *****************
|
||||||
## debugging support
|
## debugging support
|
||||||
## *****************
|
## *****************
|
||||||
|
@ -196,7 +198,7 @@ delim="-------------------------------------------------------------------"
|
||||||
echo $delim | tr '-' '*'
|
echo $delim | tr '-' '*'
|
||||||
echo "Modules to build:"
|
echo "Modules to build:"
|
||||||
res=
|
res=
|
||||||
for module in fshadow regex log pgsql mysql
|
for module in fshadow regex log pgsql mysql ldaphome
|
||||||
do
|
do
|
||||||
modname=pam_$module
|
modname=pam_$module
|
||||||
eval enable=\${build_$module}
|
eval enable=\${build_$module}
|
||||||
|
@ -216,7 +218,8 @@ build_fshadow=$build_fshadow
|
||||||
build_regex=$build_regex
|
build_regex=$build_regex
|
||||||
build_log=$build_log
|
build_log=$build_log
|
||||||
build_pgsql=$build_pgsql
|
build_pgsql=$build_pgsql
|
||||||
build_mysql=$build_mysql])
|
build_mysql=$build_mysql
|
||||||
|
build_ldaphome=$build_ldaphome])
|
||||||
|
|
||||||
AC_OUTPUT(Makefile
|
AC_OUTPUT(Makefile
|
||||||
doc/Makefile
|
doc/Makefile
|
||||||
|
@ -225,4 +228,5 @@ AC_OUTPUT(Makefile
|
||||||
pam_regex/Makefile
|
pam_regex/Makefile
|
||||||
pam_log/Makefile
|
pam_log/Makefile
|
||||||
pam_sql/Makefile
|
pam_sql/Makefile
|
||||||
|
pam_ldaphome/Makefile
|
||||||
pamck/Makefile)
|
pamck/Makefile)
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
lib_LTLIBRARIES = libgraypam.la
|
lib_LTLIBRARIES = libgraypam.la
|
||||||
|
|
||||||
libgraypam_la_SOURCES = \
|
libgraypam_la_SOURCES = \
|
||||||
|
env.c\
|
||||||
log.c\
|
log.c\
|
||||||
mem.c\
|
mem.c\
|
||||||
slist.c\
|
slist.c\
|
||||||
|
|
168
lib/env.c
Normal file
168
lib/env.c
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
/* This file is part of pam-modules.
|
||||||
|
Copyright (C) 2008, 2010-2012 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>
|
||||||
|
|
||||||
|
char *
|
||||||
|
gray_env_get(struct gray_env *env, const char *name)
|
||||||
|
{
|
||||||
|
for (; env; env = env->next)
|
||||||
|
if (strcmp(env->name, name) == 0)
|
||||||
|
return env->value;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gray_env_free(struct gray_env *env)
|
||||||
|
{
|
||||||
|
while (env) {
|
||||||
|
struct gray_env *next = env->next;
|
||||||
|
free(env->name);
|
||||||
|
free(env);
|
||||||
|
env = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gray_env_read(const char *file_name, struct gray_env **penv)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char *p;
|
||||||
|
int rc = 0;
|
||||||
|
int line = 0;
|
||||||
|
char buf[128];
|
||||||
|
gray_slist_t slist = NULL;
|
||||||
|
struct gray_env *config_env = NULL;
|
||||||
|
|
||||||
|
fp = fopen(file_name, "r");
|
||||||
|
if (!fp) {
|
||||||
|
_pam_log(LOG_ERR, "cannot open configuration file `%s': %s",
|
||||||
|
file_name, strerror (errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_env = NULL;
|
||||||
|
while (p = fgets(buf, sizeof buf, fp)) {
|
||||||
|
int len;
|
||||||
|
struct gray_env *env;
|
||||||
|
|
||||||
|
line++;
|
||||||
|
while (*p && isspace(*p))
|
||||||
|
p++;
|
||||||
|
len = strlen(p);
|
||||||
|
if (len == 0)
|
||||||
|
continue;
|
||||||
|
if (p[len-1] != '\n') {
|
||||||
|
if (!slist)
|
||||||
|
slist = gray_slist_create();
|
||||||
|
gray_slist_append(slist, p, len);
|
||||||
|
while (p = fgets(buf, sizeof buf, fp)) {
|
||||||
|
len = strlen(p);
|
||||||
|
gray_slist_append(slist, p, len);
|
||||||
|
if (p[len - 1] == '\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gray_slist_append_char(slist, 0);
|
||||||
|
p = gray_slist_finish(slist);
|
||||||
|
len = strlen(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
p[len-1] = 0;
|
||||||
|
len = gray_trim_ws(p);
|
||||||
|
|
||||||
|
if (*p == 0 || *p == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (p[len-1] == '\\') {
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
/* Collect continuation lines */
|
||||||
|
if (!slist)
|
||||||
|
slist = gray_slist_create();
|
||||||
|
do {
|
||||||
|
gray_slist_append(slist, p, len - 1);
|
||||||
|
p = fgets (buf, sizeof buf, fp);
|
||||||
|
if (!p)
|
||||||
|
break;
|
||||||
|
line++;
|
||||||
|
len = strlen(p);
|
||||||
|
if (len == 0)
|
||||||
|
break;
|
||||||
|
if (p[len-1] != '\n') {
|
||||||
|
_pam_log(LOG_EMERG,
|
||||||
|
"%s:%d: string too long",
|
||||||
|
file_name, line);
|
||||||
|
err = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p[len-1] = 0;
|
||||||
|
len = gray_trim_ws(p);
|
||||||
|
} while (p[len-1] == '\\');
|
||||||
|
if (len)
|
||||||
|
gray_slist_append(slist, p, len);
|
||||||
|
gray_slist_append_char(slist, 0);
|
||||||
|
p = gray_slist_finish(slist);
|
||||||
|
if (err)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
env = malloc(sizeof *env);
|
||||||
|
if (!env) {
|
||||||
|
_pam_log(LOG_EMERG, "not enough memory");
|
||||||
|
rc = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
env->name = strdup(p);
|
||||||
|
if (!env->name) {
|
||||||
|
_pam_log(LOG_EMERG, "not enough memory");
|
||||||
|
free(env);
|
||||||
|
rc = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (p = env->name; *p && !isspace(*p); p++)
|
||||||
|
;
|
||||||
|
if (*p)
|
||||||
|
*p++ = 0;
|
||||||
|
for (; *p && isspace(*p); p++)
|
||||||
|
;
|
||||||
|
if (!*p) {
|
||||||
|
_pam_log(LOG_EMERG, "%s:%d: not enough fields",
|
||||||
|
file_name, line);
|
||||||
|
free(env->name);
|
||||||
|
free(env);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
env->value = p;
|
||||||
|
env->next = config_env;
|
||||||
|
config_env = env;
|
||||||
|
}
|
||||||
|
|
||||||
|
gray_slist_free(&slist);
|
||||||
|
fclose(fp);
|
||||||
|
*penv = config_env;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gray_boolean_true_p(const char *value)
|
||||||
|
{
|
||||||
|
return strcmp(value, "yes") == 0
|
||||||
|
|| strcmp(value, "true") == 0
|
||||||
|
|| strcmp(value, "t") == 0;
|
||||||
|
}
|
||||||
|
|
|
@ -196,5 +196,19 @@ struct keyword *gray_find_keyword(struct keyword *kwtab, const char *str,
|
||||||
|
|
||||||
|
|
||||||
int gray_trim_ws(char *str);
|
int gray_trim_ws(char *str);
|
||||||
|
|
||||||
|
/* configuration file support */
|
||||||
|
|
||||||
|
struct gray_env {
|
||||||
|
struct gray_env *next;
|
||||||
|
char *name;
|
||||||
|
char *value;
|
||||||
|
};
|
||||||
|
|
||||||
|
char *gray_env_get(struct gray_env *env, const char *name);
|
||||||
|
void gray_env_free(struct gray_env *env);
|
||||||
|
int gray_env_read(const char *file_name, struct gray_env **penv);
|
||||||
|
|
||||||
|
int gray_boolean_true_p(const char *value);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,9 +14,7 @@
|
||||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
pamdir=@PAMDIR@
|
pamdir=@PAMDIR@
|
||||||
PAM_FSHADOW = pam_fshadow.la
|
pam_LTLIBRARIES = pam_fshadow.la
|
||||||
pam_LTLIBRARIES = @BUILD_PAM_FSHADOW@
|
|
||||||
EXTRA_LTLIBRARIES = pam_fshadow.la
|
|
||||||
pam_fshadow_la_SOURCES = pam_fshadow.c
|
pam_fshadow_la_SOURCES = pam_fshadow.c
|
||||||
AM_CPPFLAGS=-DMODULE_NAME=\"pam_fshadow\" -DSYSCONFDIR=\"${sysconfdir}\"
|
AM_CPPFLAGS=-DMODULE_NAME=\"pam_fshadow\" -DSYSCONFDIR=\"${sysconfdir}\"
|
||||||
|
|
||||||
|
|
23
pam_ldaphome/Makefile.am
Normal file
23
pam_ldaphome/Makefile.am
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# This file is part of pam-modules.
|
||||||
|
# Copyright (C) 2012 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 $(top_srcdir)/Make.rules
|
||||||
|
|
||||||
|
pamdir=@PAMDIR@
|
||||||
|
pam_LTLIBRARIES = pam_ldaphome.la
|
||||||
|
AM_CPPFLAGS=-DMODULE_NAME=\"pam_ldaphome\" -DSYSCONFDIR=\"${sysconfdir}\"
|
||||||
|
pam_ldaphome_la_SOURCES = pam_ldaphome.c
|
||||||
|
pam_ldaphome_la_LIBADD = @PAM_MISC@ -lldap
|
865
pam_ldaphome/pam_ldaphome.c
Normal file
865
pam_ldaphome/pam_ldaphome.c
Normal file
|
@ -0,0 +1,865 @@
|
||||||
|
/* This file is part of pam-modules.
|
||||||
|
Copyright (C) 2005-2008, 2010-2011 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/>. */
|
||||||
|
|
||||||
|
#ifdef HAVE__PAM_ACONF_H
|
||||||
|
# include <security/_pam_aconf.h>
|
||||||
|
#endif
|
||||||
|
#ifndef LINUX_PAM
|
||||||
|
# include <security/pam_appl.h>
|
||||||
|
#endif /* LINUX_PAM */
|
||||||
|
#include <security/pam_modules.h>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ldap.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <grp.h>
|
||||||
|
|
||||||
|
#include "graypam.h"
|
||||||
|
|
||||||
|
/* indicate the following groups are defined */
|
||||||
|
#define PAM_SM_AUTH
|
||||||
|
|
||||||
|
static long debug_level;
|
||||||
|
static int cntl_flags;
|
||||||
|
static char *config_file_name;
|
||||||
|
static int ldap_debug_level;
|
||||||
|
/* FIXME: This should be read from sshd_config */
|
||||||
|
static char *authorized_keys_file=".ssh/authorized_keys";
|
||||||
|
|
||||||
|
struct pam_opt pam_opt[] = {
|
||||||
|
{ PAM_OPTSTR(debug), pam_opt_long, &debug_level },
|
||||||
|
{ PAM_OPTSTR(debug), pam_opt_const, &debug_level, { 1 } },
|
||||||
|
{ PAM_OPTSTR(audit), pam_opt_bitmask, &cntl_flags, { CNTL_AUDIT } },
|
||||||
|
{ PAM_OPTSTR(waitdebug), pam_opt_null, NULL, { 0 },
|
||||||
|
gray_wait_debug_fun },
|
||||||
|
{ PAM_OPTSTR(config), pam_opt_string, &config_file_name },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
_pam_parse(pam_handle_t *pamh, int argc, const char **argv)
|
||||||
|
{
|
||||||
|
cntl_flags = 0;
|
||||||
|
debug_level = 0;
|
||||||
|
config_file_name = SYSCONFDIR "/" MODULE_NAME ".conf";
|
||||||
|
gray_log_init(0, MODULE_NAME, LOG_AUTHPRIV);
|
||||||
|
gray_parseopt(pam_opt, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
argcv_free(int wc, char **wv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < wc; i++) {
|
||||||
|
free(wv[i]);
|
||||||
|
free(wv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
argcv_split(const char *str, int *pargc, char ***pargv)
|
||||||
|
{
|
||||||
|
int argc, i;
|
||||||
|
char **argv;
|
||||||
|
const char *p;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
argc = 1;
|
||||||
|
for (p = str; *p; p++) {
|
||||||
|
if (*p == ' ')
|
||||||
|
argc++;
|
||||||
|
}
|
||||||
|
argv = calloc(argc + 1, sizeof(argv[0]));
|
||||||
|
if (!argv)
|
||||||
|
return 1;
|
||||||
|
for (i = 0, p = str;;) {
|
||||||
|
size_t len = strcspn(p, " ");
|
||||||
|
char *q = malloc(len + 1);
|
||||||
|
|
||||||
|
if (!q) {
|
||||||
|
rc = errno;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(q, p, len);
|
||||||
|
q[len] = 0;
|
||||||
|
argv[i++] = q;
|
||||||
|
p += len;
|
||||||
|
if (p)
|
||||||
|
p += strspn(p, " ");
|
||||||
|
if (!*p)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc) {
|
||||||
|
argcv_free(argc, argv);
|
||||||
|
errno = rc;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
argv[i] = NULL;
|
||||||
|
*pargc = argc;
|
||||||
|
*pargv = argv;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
argcv_concat(int wc, char **wv)
|
||||||
|
{
|
||||||
|
char *res, *p;
|
||||||
|
size_t size = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < wc; i++)
|
||||||
|
size += strlen(wv[i]) + 1;
|
||||||
|
size++;
|
||||||
|
res = malloc(size);
|
||||||
|
if (!res)
|
||||||
|
return 0;
|
||||||
|
for (p = res, i = 0; ; i++) {
|
||||||
|
strcpy(p, wv[i]);
|
||||||
|
p += strlen(wv[i]);
|
||||||
|
if (i < wc)
|
||||||
|
*p++ = ' ';
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*p = 0;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
parse_ldap_uri(const char *uri)
|
||||||
|
{
|
||||||
|
int wc;
|
||||||
|
char **wv;
|
||||||
|
LDAPURLDesc *ludlist, **ludp;
|
||||||
|
char **urls = NULL;
|
||||||
|
int nurls = 0;
|
||||||
|
char *ldapuri = NULL;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = ldap_url_parse(uri, &ludlist);
|
||||||
|
if (rc != LDAP_URL_SUCCESS) {
|
||||||
|
_pam_log(LOG_ERR, "cannot parse LDAP URL(s)=%s (%d)",
|
||||||
|
uri, rc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ludp = &ludlist; *ludp; ) {
|
||||||
|
LDAPURLDesc *lud = *ludp;
|
||||||
|
char **tmp;
|
||||||
|
|
||||||
|
if (lud->lud_dn && lud->lud_dn[0]
|
||||||
|
&& (lud->lud_host == NULL || lud->lud_host[0] == '\0')) {
|
||||||
|
/* if no host but a DN is provided, try
|
||||||
|
DNS SRV to gather the host list */
|
||||||
|
char *domain = NULL, *hostlist = NULL;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (ldap_dn2domain (lud->lud_dn, &domain) ||
|
||||||
|
!domain) {
|
||||||
|
_pam_log(LOG_ERR,
|
||||||
|
"DNS SRV: cannot convert "
|
||||||
|
"DN=\"%s\" into a domain",
|
||||||
|
lud->lud_dn);
|
||||||
|
goto dnssrv_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ldap_domain2hostlist(domain, &hostlist);
|
||||||
|
if (rc) {
|
||||||
|
_pam_log(LOG_ERR,
|
||||||
|
"DNS SRV: cannot convert "
|
||||||
|
"domain=%s into a hostlist",
|
||||||
|
domain);
|
||||||
|
goto dnssrv_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argcv_split(hostlist, &wc, &wv)) {
|
||||||
|
_pam_log(LOG_ERR,
|
||||||
|
"DNS SRV: could not parse "
|
||||||
|
"hostlist=\"%s\": %s",
|
||||||
|
hostlist, strerror(errno));
|
||||||
|
goto dnssrv_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = realloc(urls, sizeof(char *) * (nurls + wc + 1));
|
||||||
|
if (!tmp) {
|
||||||
|
_pam_log(LOG_ERR,
|
||||||
|
"DNS SRV %s", strerror(errno));
|
||||||
|
goto dnssrv_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
urls = tmp;
|
||||||
|
urls[nurls] = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < wc; i++) {
|
||||||
|
char *p = malloc(strlen(lud->lud_scheme) +
|
||||||
|
strlen(wv[i]) +
|
||||||
|
3);
|
||||||
|
if (!p) {
|
||||||
|
_pam_log(LOG_ERR, "DNS SRV %s",
|
||||||
|
strerror(errno));
|
||||||
|
goto dnssrv_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(p, lud->lud_scheme);
|
||||||
|
strcat(p, "//");
|
||||||
|
strcat(p, wv[i]);
|
||||||
|
|
||||||
|
urls[nurls + i + 1] = NULL;
|
||||||
|
urls[nurls + i] = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
nurls += i;
|
||||||
|
|
||||||
|
dnssrv_free:
|
||||||
|
argcv_free(wc, wv);
|
||||||
|
ber_memfree(hostlist);
|
||||||
|
ber_memfree(domain);
|
||||||
|
} else {
|
||||||
|
tmp = realloc(urls, sizeof(char *) * (nurls + 2));
|
||||||
|
if (!tmp) {
|
||||||
|
_pam_log(LOG_ERR,
|
||||||
|
"DNS SRV %s", strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
urls = tmp;
|
||||||
|
urls[nurls + 1] = NULL;
|
||||||
|
|
||||||
|
urls[nurls] = ldap_url_desc2str(lud);
|
||||||
|
if (!urls[nurls]) {
|
||||||
|
_pam_log(LOG_ERR, "DNS SRV %s",
|
||||||
|
strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nurls++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ludp = lud->lud_next;
|
||||||
|
|
||||||
|
lud->lud_next = NULL;
|
||||||
|
ldap_free_urldesc(lud);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ludlist) {
|
||||||
|
ldap_free_urldesc (ludlist);
|
||||||
|
return NULL;
|
||||||
|
} else if (!urls)
|
||||||
|
return NULL;
|
||||||
|
ldapuri = argcv_concat(wc, wv);
|
||||||
|
if (!ldapuri)
|
||||||
|
_pam_log(LOG_ERR, "%s", strerror(errno));
|
||||||
|
ber_memvfree ((void **)urls);
|
||||||
|
return ldapuri;
|
||||||
|
}
|
||||||
|
|
||||||
|
static LDAP *
|
||||||
|
ldap_connect(struct gray_env *env)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
char *ldapuri = NULL;
|
||||||
|
LDAP *ld = NULL;
|
||||||
|
int protocol = LDAP_VERSION3; /* FIXME: must be configurable */
|
||||||
|
char *val;
|
||||||
|
|
||||||
|
if (ldap_debug_level) {
|
||||||
|
if (ber_set_option (NULL, LBER_OPT_DEBUG_LEVEL,
|
||||||
|
&ldap_debug_level)
|
||||||
|
!= LBER_OPT_SUCCESS )
|
||||||
|
_pam_log(LOG_ERR,
|
||||||
|
"cannot set LBER_OPT_DEBUG_LEVEL %d",
|
||||||
|
ldap_debug_level);
|
||||||
|
|
||||||
|
if (ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL,
|
||||||
|
&ldap_debug_level)
|
||||||
|
!= LDAP_OPT_SUCCESS )
|
||||||
|
_pam_log(LOG_ERR,
|
||||||
|
"could not set LDAP_OPT_DEBUG_LEVEL %d",
|
||||||
|
ldap_debug_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
val = gray_env_get(env, "uri");
|
||||||
|
if (val) {
|
||||||
|
ldapuri = parse_ldap_uri(val);
|
||||||
|
if (!ldapuri)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
DEBUG(2, ("constructed LDAP URI: %s",
|
||||||
|
ldapuri ? ldapuri : "<DEFAULT>"));
|
||||||
|
|
||||||
|
rc = ldap_initialize(&ld, ldapuri);
|
||||||
|
if (rc != LDAP_SUCCESS) {
|
||||||
|
_pam_log(LOG_ERR,
|
||||||
|
"cannot create LDAP session handle for "
|
||||||
|
"URI=%s (%d): %s",
|
||||||
|
ldapuri, rc, ldap_err2string(rc));
|
||||||
|
free(ldapuri);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
free(ldapuri);
|
||||||
|
|
||||||
|
val = gray_env_get(env, "tls");
|
||||||
|
|
||||||
|
if (val && gray_boolean_true_p(val)) {
|
||||||
|
rc = ldap_start_tls_s(ld, NULL, NULL);
|
||||||
|
if (rc != LDAP_SUCCESS) {
|
||||||
|
_pam_log(LOG_ERR,
|
||||||
|
"ldap_start_tls failed: %s",
|
||||||
|
ldap_err2string(rc));
|
||||||
|
/* try to continue anyway, to avoid memory
|
||||||
|
leek (ld not being freed) */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &protocol);
|
||||||
|
|
||||||
|
/* FIXME: Timeouts, SASL, etc. */
|
||||||
|
return ld;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ldap_bind (LDAP *ld, struct gray_env *env)
|
||||||
|
{
|
||||||
|
int msgid, err, rc;
|
||||||
|
LDAPMessage *result;
|
||||||
|
LDAPControl **ctrls;
|
||||||
|
char msgbuf[256];
|
||||||
|
char *matched = NULL;
|
||||||
|
char *info = NULL;
|
||||||
|
char **refs = NULL;
|
||||||
|
static struct berval passwd;
|
||||||
|
char *binddn;
|
||||||
|
|
||||||
|
binddn = gray_env_get(env, "binddn");
|
||||||
|
passwd.bv_val = gray_env_get(env, "bindpw");
|
||||||
|
passwd.bv_len = passwd.bv_val ? strlen(passwd.bv_val) : 0;
|
||||||
|
|
||||||
|
msgbuf[0] = 0;
|
||||||
|
|
||||||
|
rc = ldap_sasl_bind(ld, binddn, LDAP_SASL_SIMPLE, &passwd,
|
||||||
|
NULL, NULL, &msgid);
|
||||||
|
if (msgid == -1) {
|
||||||
|
_pam_log(LOG_ERR,
|
||||||
|
"ldap_sasl_bind(SIMPLE) failed: %s",
|
||||||
|
ldap_err2string(rc));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ldap_result(ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1) {
|
||||||
|
_pam_log(LOG_ERR, "ldap_result failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ldap_parse_result(ld, result, &err, &matched, &info, &refs,
|
||||||
|
&ctrls, 1);
|
||||||
|
if (rc != LDAP_SUCCESS) {
|
||||||
|
_pam_log(LOG_ERR, "ldap_parse_result failed: %s",
|
||||||
|
ldap_err2string (rc));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctrls)
|
||||||
|
ldap_controls_free(ctrls);
|
||||||
|
|
||||||
|
if (err != LDAP_SUCCESS
|
||||||
|
|| msgbuf[0]
|
||||||
|
|| (matched && matched[0])
|
||||||
|
|| (info && info[0])
|
||||||
|
|| refs) {
|
||||||
|
/* FIXME: Use debug output for that */
|
||||||
|
DEBUG(2,("ldap_bind: %s (%d)%s",
|
||||||
|
ldap_err2string(err), err, msgbuf));
|
||||||
|
|
||||||
|
if (matched && *matched)
|
||||||
|
DEBUG(2,("matched DN: %s", matched));
|
||||||
|
|
||||||
|
if (info && *info)
|
||||||
|
DEBUG(2,("additional info: %s", info));
|
||||||
|
|
||||||
|
if (refs && *refs) {
|
||||||
|
int i;
|
||||||
|
DEBUG(3,("referrals:"));
|
||||||
|
for (i = 0; refs[i]; i++)
|
||||||
|
DEBUG(3,("%s", refs[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matched)
|
||||||
|
ber_memfree(matched);
|
||||||
|
if (info)
|
||||||
|
ber_memfree(info);
|
||||||
|
if (refs)
|
||||||
|
ber_memvfree((void **)refs);
|
||||||
|
|
||||||
|
return !(err == LDAP_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ldap_unbind(LDAP *ld)
|
||||||
|
{
|
||||||
|
if (ld) {
|
||||||
|
ldap_set_option(ld, LDAP_OPT_SERVER_CONTROLS, NULL);
|
||||||
|
ldap_unbind_ext(ld, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
get_ldap_attr(LDAP *ld, LDAPMessage *msg, const char *attr)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
BerElement *ber = NULL;
|
||||||
|
struct berval bv;
|
||||||
|
char *ufn = NULL;
|
||||||
|
char *val;
|
||||||
|
struct berval **values;
|
||||||
|
|
||||||
|
rc = ldap_get_dn_ber(ld, msg, &ber, &bv);
|
||||||
|
ufn = ldap_dn2ufn(bv.bv_val);
|
||||||
|
DEBUG(2, ("INFO: %s", ufn));
|
||||||
|
ldap_memfree(ufn);
|
||||||
|
|
||||||
|
values = ldap_get_values_len(ld, msg, attr);
|
||||||
|
if (!values || !values[0]) {
|
||||||
|
_pam_log(LOG_ERR,
|
||||||
|
"LDAP attribute `%s' has NULL value",
|
||||||
|
attr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
val = strdup(values[0]->bv_val);
|
||||||
|
if (!val)
|
||||||
|
_pam_log(LOG_ERR, "%s", strerror(errno));
|
||||||
|
else
|
||||||
|
DEBUG(1, ("pubkey: %s", val));
|
||||||
|
ldap_value_free_len(values);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
ldap_search(LDAP *ld, const char *base, const char *filter, const char *attr)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
LDAPMessage *res, *msg;
|
||||||
|
ber_int_t msgid;
|
||||||
|
char *attrs[2];
|
||||||
|
char *ret;
|
||||||
|
|
||||||
|
attrs[0] = (char*) attr;
|
||||||
|
attrs[1] = NULL;
|
||||||
|
rc = ldap_search_ext(ld, base, LDAP_SCOPE_SUBTREE,
|
||||||
|
filter, attrs, 0,
|
||||||
|
NULL, NULL, NULL, -1, &msgid);
|
||||||
|
|
||||||
|
if (rc != LDAP_SUCCESS) {
|
||||||
|
_pam_log(LOG_ERR, "ldap_search_ext: %s", ldap_err2string(rc));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ldap_result(ld, msgid, LDAP_MSG_ALL, NULL, &res);
|
||||||
|
if (rc < 0) {
|
||||||
|
_pam_log(LOG_ERR, "ldap_result failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ldap_count_entries(ld, res);
|
||||||
|
if (rc == 0) {
|
||||||
|
_pam_log(LOG_ERR, "not enough entires");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (rc > 1)
|
||||||
|
_pam_log(LOG_NOTICE, "LDAP: too many entries for filter %s",
|
||||||
|
filter);
|
||||||
|
|
||||||
|
msg = ldap_first_entry(ld, res);
|
||||||
|
ret = get_ldap_attr(ld, msg, attr);
|
||||||
|
ldap_msgfree(res);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_intval(struct gray_env *env, const char *name, unsigned long *pv)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
char *v = gray_env_get(env, name);
|
||||||
|
|
||||||
|
if (!v)
|
||||||
|
return 1;
|
||||||
|
*pv = strtoul(v, &p, 10);
|
||||||
|
if (*p) {
|
||||||
|
_pam_log(LOG_ERR, "configuration variable %s is not integer",
|
||||||
|
name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
check_groups(int gc, char **gv, const char *username)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < gc; i++) {
|
||||||
|
struct group *gp = getgrnam(gv[i]);
|
||||||
|
if (gp) {
|
||||||
|
char **p;
|
||||||
|
for (p = gp->gr_mem; *p; p++)
|
||||||
|
if (strcmp(username, *p) == 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
check_user_groups(pam_handle_t *pamh, struct gray_env *env,
|
||||||
|
struct passwd **ppw, int *retval)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
const char *username;
|
||||||
|
struct passwd *pw;
|
||||||
|
unsigned long ival;
|
||||||
|
char *sval;
|
||||||
|
|
||||||
|
rc = pam_get_user(pamh, &username, NULL);
|
||||||
|
if (rc != PAM_SUCCESS || !username) {
|
||||||
|
DEBUG(1,("can not get the username"));
|
||||||
|
*retval = rc;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
pw = getpwnam(username);
|
||||||
|
if (!pw) {
|
||||||
|
*retval = PAM_USER_UNKNOWN;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
*ppw = pw;
|
||||||
|
if (get_intval(env, "min-uid", &ival) == 0) {
|
||||||
|
if (pw->pw_uid < ival) {
|
||||||
|
DEBUG(10, ("ignoring user %s: has UID < %lu",
|
||||||
|
username, ival));
|
||||||
|
*retval = PAM_SUCCESS;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (get_intval(env, "min-gid", &ival) == 0) {
|
||||||
|
if (pw->pw_gid < ival) {
|
||||||
|
DEBUG(10, ("ignoring user %s: has GID < %lu",
|
||||||
|
username, ival));
|
||||||
|
*retval = PAM_SUCCESS;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sval = gray_env_get(env, "allow-groups");
|
||||||
|
if (sval) {
|
||||||
|
int gc;
|
||||||
|
char **gv;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (argcv_split(sval, &gc, &gv)) {
|
||||||
|
_pam_log(LOG_ERR, "cannot split allow-groups: %s",
|
||||||
|
strerror(errno));
|
||||||
|
*retval = PAM_AUTH_ERR;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
rc = check_groups(gc, gv, username);
|
||||||
|
argcv_free(gc, gv);
|
||||||
|
if (rc) {
|
||||||
|
DEBUG(10, ("ignoring user %s: not in allowed group list",
|
||||||
|
username, ival));
|
||||||
|
*retval = PAM_SUCCESS;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
populate_homedir(struct passwd *pw, const char *skel)
|
||||||
|
{
|
||||||
|
// FIXME!!!
|
||||||
|
_pam_log(LOG_ERR, "populate_homedir is not yet implemented!");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the directory DIR, eventually creating all intermediate directories
|
||||||
|
starting from DIR + BASELEN. */
|
||||||
|
int
|
||||||
|
create_hierarchy(char *dir, size_t baselen)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct stat st;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if (stat(dir, &st) == 0) {
|
||||||
|
if (!S_ISDIR(st.st_mode)) {
|
||||||
|
_pam_log(LOG_ERR, "component %s is not a directory",
|
||||||
|
dir);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else if (errno != ENOENT) {
|
||||||
|
_pam_log(LOG_ERR, "cannot stat file %s: %s",
|
||||||
|
dir, strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = strrchr(dir, '/');
|
||||||
|
if (p) {
|
||||||
|
if (p - dir + 1 < baselen) {
|
||||||
|
_pam_log(LOG_ERR, "base directory %s does not exist",
|
||||||
|
dir);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
*p = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = create_hierarchy(dir, baselen);
|
||||||
|
if (rc == 0) {
|
||||||
|
if (p)
|
||||||
|
*p = '/';
|
||||||
|
if (mkdir(dir, 0755)) {
|
||||||
|
_pam_log(LOG_ERR, "cannot create directory %s: %s",
|
||||||
|
dir, strerror(errno));
|
||||||
|
rc = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
create_interdir(const char *path, struct passwd *pw)
|
||||||
|
{
|
||||||
|
char *dir, *p;
|
||||||
|
size_t len;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
p = strrchr(path, '/');
|
||||||
|
if (!p)
|
||||||
|
return 1;
|
||||||
|
len = p - path;
|
||||||
|
dir = gray_malloc(len + 1);
|
||||||
|
memcpy(dir, path, len);
|
||||||
|
dir[len] = 0;
|
||||||
|
rc = create_hierarchy(dir, strlen(pw->pw_dir));
|
||||||
|
if (rc == 0)
|
||||||
|
chown(dir, pw->pw_uid, pw->pw_gid);
|
||||||
|
free(dir);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
store_pubkey(const char *key, struct passwd *pw)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
const char *kp;
|
||||||
|
int c;
|
||||||
|
int found = 0;
|
||||||
|
char *file_name;
|
||||||
|
size_t homelen, pathlen, len;
|
||||||
|
|
||||||
|
homelen = strlen(pw->pw_dir);
|
||||||
|
pathlen = strlen(authorized_keys_file);
|
||||||
|
len = homelen + pathlen;
|
||||||
|
if (pw->pw_dir[homelen - 1] != '/')
|
||||||
|
len++;
|
||||||
|
file_name = gray_malloc(len + 1);
|
||||||
|
memcpy(file_name, pw->pw_dir, homelen);
|
||||||
|
if (pw->pw_dir[homelen - 1] != '/')
|
||||||
|
file_name[homelen++] = '/';
|
||||||
|
strcpy(file_name + homelen, authorized_keys_file);
|
||||||
|
|
||||||
|
fp = fopen(file_name, "a+");
|
||||||
|
if (!fp && create_interdir(file_name, pw) == 0)
|
||||||
|
fp = fopen(file_name, "a+");
|
||||||
|
if (!fp) {
|
||||||
|
_pam_log(LOG_EMERG, "cannot open file %s: %s",
|
||||||
|
file_name, strerror(errno));
|
||||||
|
free(file_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
free(file_name);
|
||||||
|
fchown(fileno(fp), pw->pw_uid, pw->pw_gid);
|
||||||
|
|
||||||
|
kp = key;
|
||||||
|
while (!feof(fp)) {
|
||||||
|
while (*kp && (c = getc(fp)) != EOF && c == *kp)
|
||||||
|
kp++;
|
||||||
|
if (*kp == 0) {
|
||||||
|
DEBUG(2, ("key found"));
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
kp = key;
|
||||||
|
if (c != '\n') {
|
||||||
|
if (c != EOF) {
|
||||||
|
while ((c = getc(fp)) != EOF && c != '\n')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
if (c == EOF) {
|
||||||
|
if (ftell(fp))
|
||||||
|
fputc('\n', fp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
fwrite(key, strlen(key), 1, fp);
|
||||||
|
fputc('\n', fp);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
import_public_key(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env)
|
||||||
|
{
|
||||||
|
LDAP *ld;
|
||||||
|
int retval;
|
||||||
|
const char *base = gray_env_get(env, "base");
|
||||||
|
const char *filter_pat = gray_env_get(env, "filter");
|
||||||
|
const char *attr = gray_env_get(env, "pubkey-attr");
|
||||||
|
|
||||||
|
if (!filter_pat) {
|
||||||
|
_pam_log(LOG_ERR, "configuration variable `filter' not set");
|
||||||
|
return PAM_SERVICE_ERR;
|
||||||
|
}
|
||||||
|
if (!attr) {
|
||||||
|
_pam_log(LOG_ERR, "configuration variable `attr' not set");
|
||||||
|
return PAM_SERVICE_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ld = ldap_connect(env);
|
||||||
|
if (!ld)
|
||||||
|
return PAM_SERVICE_ERR;
|
||||||
|
if (ldap_bind(ld, env))
|
||||||
|
retval = PAM_SERVICE_ERR;
|
||||||
|
else {
|
||||||
|
char *filter;
|
||||||
|
gray_slist_t slist;
|
||||||
|
char *pubkey;
|
||||||
|
|
||||||
|
slist = gray_slist_create();
|
||||||
|
gray_expand_string(pamh, filter_pat, slist);
|
||||||
|
gray_slist_append_char(slist, 0);
|
||||||
|
filter = gray_slist_finish(slist);
|
||||||
|
|
||||||
|
pubkey = ldap_search(ld, base, filter, attr);
|
||||||
|
gray_slist_free(&slist);
|
||||||
|
store_pubkey(pubkey, pw);
|
||||||
|
free(pubkey);
|
||||||
|
retval = PAM_SUCCESS;
|
||||||
|
}
|
||||||
|
ldap_unbind(ld);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
create_home_dir(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
if (stat(pw->pw_dir, &st)) {
|
||||||
|
if (errno != ENOENT) {
|
||||||
|
_pam_log(LOG_ERR, "cannot stat home directory %s: %s",
|
||||||
|
pw->pw_dir, strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* FIXME: mode must be configurable */
|
||||||
|
if (mkdir(pw->pw_dir, 0775)) {
|
||||||
|
_pam_log(LOG_ERR, "cannot create %s: %s",
|
||||||
|
pw->pw_dir, strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
chown(pw->pw_dir, pw->pw_uid, pw->pw_gid);
|
||||||
|
} else if (!S_ISDIR(st.st_mode)) {
|
||||||
|
_pam_log(LOG_ERR, "%s exists, but is not a directory",
|
||||||
|
pw->pw_dir);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = gray_env_get(env, "skel");
|
||||||
|
if (s) {
|
||||||
|
if (stat(s, &st)) {
|
||||||
|
_pam_log(LOG_ERR, "cannot stat skeleton directory %s: %s",
|
||||||
|
pw->pw_dir, strerror(errno));
|
||||||
|
return 1;
|
||||||
|
} else if (!S_ISDIR(st.st_mode)) {
|
||||||
|
_pam_log(LOG_ERR, "%s exists, but is not a directory",
|
||||||
|
pw->pw_dir);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
populate_homedir(pw, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PAM_EXTERN int
|
||||||
|
pam_sm_authenticate(pam_handle_t *pamh,
|
||||||
|
int flags,
|
||||||
|
int argc,
|
||||||
|
const char **argv)
|
||||||
|
{
|
||||||
|
int retval = PAM_AUTH_ERR;
|
||||||
|
struct gray_env *env;
|
||||||
|
|
||||||
|
_pam_parse(pamh, argc, argv);
|
||||||
|
|
||||||
|
DEBUG(90,("enter pam_sm_authenticate"));
|
||||||
|
gray_pam_init(PAM_AUTHINFO_UNAVAIL);
|
||||||
|
if (gray_env_read(config_file_name, &env) == 0) {
|
||||||
|
struct passwd *pw;
|
||||||
|
|
||||||
|
if (check_user_groups(pamh, env, &pw, &retval) == 0) {
|
||||||
|
if (create_home_dir(pamh, pw, env) == 0 &&
|
||||||
|
import_public_key(pamh, pw, env) == 0)
|
||||||
|
retval = PAM_TRY_AGAIN;
|
||||||
|
}
|
||||||
|
gray_env_free(env);
|
||||||
|
}
|
||||||
|
DEBUG(90,("exit pam_sm_authenticate: %d", retval));
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
PAM_EXTERN int
|
||||||
|
pam_sm_setcred(pam_handle_t *pamh,
|
||||||
|
int flags,
|
||||||
|
int argc,
|
||||||
|
const char **argv)
|
||||||
|
{
|
||||||
|
return PAM_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PAM_STATIC
|
||||||
|
|
||||||
|
struct pam_module _pam_ldaphome_modstruct = {
|
||||||
|
"pam_ldaphome", /* name of the module */
|
||||||
|
pam_sm_authenticate,
|
||||||
|
pam_sm_setcred,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,8 @@
|
||||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
pamdir=@PAMDIR@
|
pamdir=@PAMDIR@
|
||||||
PAM_REGEX = pam_regex.la
|
PAM_REGEX =
|
||||||
pam_LTLIBRARIES = @BUILD_PAM_REGEX@
|
pam_LTLIBRARIES = pam_regex.la
|
||||||
EXTRA_LTLIBRARIES = pam_regex.la
|
|
||||||
pam_regex_la_SOURCES = pam_regex.c
|
pam_regex_la_SOURCES = pam_regex.c
|
||||||
AM_CPPFLAGS=-DMODULE_NAME=\"pam_regex\" -DSYSCONFDIR=\"${sysconfdir}\"
|
AM_CPPFLAGS=-DMODULE_NAME=\"pam_regex\" -DSYSCONFDIR=\"${sysconfdir}\"
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,7 @@ pam_sm_setcred(pam_handle_t *pamh,
|
||||||
|
|
||||||
#ifdef PAM_STATIC
|
#ifdef PAM_STATIC
|
||||||
|
|
||||||
struct pam_module _pam_radius_modstruct = {
|
struct pam_module _pam_regex_modstruct = {
|
||||||
"pam_regex", /* name of the module */
|
"pam_regex", /* name of the module */
|
||||||
pam_sm_authenticate,
|
pam_sm_authenticate,
|
||||||
pam_sm_setcred,
|
pam_sm_setcred,
|
||||||
|
|
|
@ -141,44 +141,12 @@ _pam_get_password(pam_handle_t *pamh, char **password, const char *prompt)
|
||||||
|
|
||||||
|
|
||||||
/* Configuration */
|
/* Configuration */
|
||||||
typedef struct config_env env_t;
|
static struct gray_env *config_env;
|
||||||
struct config_env {
|
|
||||||
env_t *next;
|
|
||||||
char *name;
|
|
||||||
char *value;
|
|
||||||
};
|
|
||||||
static env_t *config_env;
|
|
||||||
|
|
||||||
char *
|
char *
|
||||||
gpam_sql_find_config(const char *name)
|
gpam_sql_find_config(const char *name)
|
||||||
{
|
{
|
||||||
env_t *env;
|
return gray_env_get(config_env, name);
|
||||||
|
|
||||||
for (env = config_env; env; env = env->next)
|
|
||||||
if (strcmp(env->name, name) == 0)
|
|
||||||
return env->value;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
free_config()
|
|
||||||
{
|
|
||||||
env_t *env = config_env;
|
|
||||||
while (env) {
|
|
||||||
env_t *next = env->next;
|
|
||||||
free(env->name);
|
|
||||||
free(env);
|
|
||||||
env = next;
|
|
||||||
}
|
|
||||||
config_env = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
boolean_true_p(const char *value)
|
|
||||||
{
|
|
||||||
return strcmp(value, "yes") == 0
|
|
||||||
|| strcmp(value, "true") == 0
|
|
||||||
|| strcmp(value, "t") == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -186,130 +154,10 @@ gpam_sql_check_boolean_config(const char *name, int defval)
|
||||||
{
|
{
|
||||||
const char *value = gpam_sql_find_config(name);
|
const char *value = gpam_sql_find_config(name);
|
||||||
if (value)
|
if (value)
|
||||||
defval = boolean_true_p(value);
|
defval = gray_boolean_true_p(value);
|
||||||
return defval;
|
return defval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
read_config ()
|
|
||||||
{
|
|
||||||
FILE *fp;
|
|
||||||
char *p;
|
|
||||||
int rc = 0;
|
|
||||||
int line = 0;
|
|
||||||
char buf[128];
|
|
||||||
gray_slist_t slist = NULL;
|
|
||||||
|
|
||||||
fp = fopen (gpam_sql_config_file, "r");
|
|
||||||
if (!fp) {
|
|
||||||
_pam_log(LOG_ERR, "cannot open configuration file `%s': %s",
|
|
||||||
gpam_sql_config_file, strerror (errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
config_env = NULL;
|
|
||||||
while (p = fgets (buf, sizeof buf, fp)) {
|
|
||||||
int len;
|
|
||||||
env_t *env;
|
|
||||||
|
|
||||||
line++;
|
|
||||||
while (*p && isspace(*p))
|
|
||||||
p++;
|
|
||||||
len = strlen(p);
|
|
||||||
if (len == 0)
|
|
||||||
continue;
|
|
||||||
if (p[len-1] != '\n') {
|
|
||||||
if (!slist)
|
|
||||||
slist = gray_slist_create();
|
|
||||||
gray_slist_append(slist, p, len);
|
|
||||||
while (p = fgets(buf, sizeof buf, fp)) {
|
|
||||||
len = strlen(p);
|
|
||||||
gray_slist_append(slist, p, len);
|
|
||||||
if (p[len - 1] == '\n')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gray_slist_append_char(slist, 0);
|
|
||||||
p = gray_slist_finish(slist);
|
|
||||||
len = strlen(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
p[len-1] = 0;
|
|
||||||
len = gray_trim_ws(p);
|
|
||||||
|
|
||||||
if (*p == 0 || *p == '#')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (p[len-1] == '\\') {
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
/* Collect continuation lines */
|
|
||||||
if (!slist)
|
|
||||||
slist = gray_slist_create();
|
|
||||||
do {
|
|
||||||
gray_slist_append(slist, p, len - 1);
|
|
||||||
p = fgets (buf, sizeof buf, fp);
|
|
||||||
if (!p)
|
|
||||||
break;
|
|
||||||
line++;
|
|
||||||
len = strlen(p);
|
|
||||||
if (len == 0)
|
|
||||||
break;
|
|
||||||
if (p[len-1] != '\n') {
|
|
||||||
_pam_log(LOG_EMERG,
|
|
||||||
"%s:%d: string too long",
|
|
||||||
gpam_sql_config_file, line);
|
|
||||||
err = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
p[len-1] = 0;
|
|
||||||
len = gray_trim_ws(p);
|
|
||||||
} while (p[len-1] == '\\');
|
|
||||||
if (len)
|
|
||||||
gray_slist_append(slist, p, len);
|
|
||||||
gray_slist_append_char(slist, 0);
|
|
||||||
p = gray_slist_finish(slist);
|
|
||||||
if (err)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
env = malloc(sizeof *env);
|
|
||||||
if (!env) {
|
|
||||||
_pam_log(LOG_EMERG, "not enough memory");
|
|
||||||
rc = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
env->name = strdup(p);
|
|
||||||
if (!env->name) {
|
|
||||||
_pam_log(LOG_EMERG, "not enough memory");
|
|
||||||
free(env);
|
|
||||||
rc = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (p = env->name; *p && !isspace(*p); p++)
|
|
||||||
;
|
|
||||||
if (*p)
|
|
||||||
*p++ = 0;
|
|
||||||
for (; *p && isspace(*p); p++)
|
|
||||||
;
|
|
||||||
if (!*p) {
|
|
||||||
_pam_log(LOG_EMERG, "%s:%d: not enough fields",
|
|
||||||
gpam_sql_config_file, line);
|
|
||||||
free(env->name);
|
|
||||||
free(env);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
env->value = p;
|
|
||||||
env->next = config_env;
|
|
||||||
config_env = env;
|
|
||||||
}
|
|
||||||
|
|
||||||
gray_slist_free(&slist);
|
|
||||||
fclose(fp);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
gpam_sql_get_query(pam_handle_t *pamh, const char *name, gray_slist_t *pslist,
|
gpam_sql_get_query(pam_handle_t *pamh, const char *name, gray_slist_t *pslist,
|
||||||
|
@ -364,7 +212,6 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
||||||
const char *username;
|
const char *username;
|
||||||
char *password;
|
char *password;
|
||||||
int retval = PAM_AUTH_ERR;
|
int retval = PAM_AUTH_ERR;
|
||||||
|
|
||||||
gray_pam_init(PAM_SERVICE_ERR);
|
gray_pam_init(PAM_SERVICE_ERR);
|
||||||
|
|
||||||
/* parse arguments */
|
/* parse arguments */
|
||||||
|
@ -386,7 +233,7 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
||||||
return PAM_SERVICE_ERR;
|
return PAM_SERVICE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read_config())
|
if (gray_env_read(gpam_sql_config_file, &config_env))
|
||||||
retval = PAM_SERVICE_ERR;
|
retval = PAM_SERVICE_ERR;
|
||||||
else {
|
else {
|
||||||
gray_slist_t slist;
|
gray_slist_t slist;
|
||||||
|
@ -399,7 +246,8 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
||||||
gray_slist_free(&slist);
|
gray_slist_free(&slist);
|
||||||
}
|
}
|
||||||
|
|
||||||
free_config();
|
gray_env_free(config_env);
|
||||||
|
config_env = NULL;
|
||||||
|
|
||||||
switch (retval) {
|
switch (retval) {
|
||||||
case PAM_ACCT_EXPIRED:
|
case PAM_ACCT_EXPIRED:
|
||||||
|
@ -433,7 +281,7 @@ sql_session_mgmt(pam_handle_t *pamh, int flags,
|
||||||
/* parse arguments */
|
/* parse arguments */
|
||||||
_pam_parse(argc, argv);
|
_pam_parse(argc, argv);
|
||||||
|
|
||||||
if (read_config())
|
if (gray_env_read(gpam_sql_config_file, &config_env))
|
||||||
retval = PAM_SERVICE_ERR;
|
retval = PAM_SERVICE_ERR;
|
||||||
else {
|
else {
|
||||||
gray_slist_t slist;
|
gray_slist_t slist;
|
||||||
|
@ -443,7 +291,8 @@ sql_session_mgmt(pam_handle_t *pamh, int flags,
|
||||||
gray_slist_free(&slist);
|
gray_slist_free(&slist);
|
||||||
}
|
}
|
||||||
|
|
||||||
free_config();
|
gray_env_free(config_env);
|
||||||
|
config_env = NULL;
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue