Allow "configure" to explicitly disable OpenSSL and PAM support. Also, allow
OpenSSL and PAM libraries to be optionally linked as regular shared libraries instead of being searched for and loaded at run-time. git-svn-id: https://shellinabox.googlecode.com/svn/trunk@65 0da03de8-d603-11dd-86c2-0f8696b7b6f9
This commit is contained in:
parent
530182d15e
commit
84dcc33650
9 changed files with 1134 additions and 254 deletions
|
@ -1,3 +1,12 @@
|
||||||
|
2009-02-16 Markus Gutschke <markus@shellinabox.com>
|
||||||
|
|
||||||
|
* Fixed various bugs that prevents ShellInABox from running on
|
||||||
|
FreeBSD
|
||||||
|
|
||||||
|
* Allow "configure" to select whether OpenSSL and PAM libraries
|
||||||
|
should be used at all, dynamically searched-for at run-time, or
|
||||||
|
linked as a regular dynamic library.
|
||||||
|
|
||||||
2009-02-12 Markus Gutschke <markus@shellinabox.com>
|
2009-02-12 Markus Gutschke <markus@shellinabox.com>
|
||||||
|
|
||||||
* Released version 2.4
|
* Released version 2.4
|
||||||
|
|
21
Makefile.am
21
Makefile.am
|
@ -79,19 +79,28 @@ shellinaboxd_LDFLAGS = -static
|
||||||
libtool: $(LIBTOOL_DEPS)
|
libtool: $(LIBTOOL_DEPS)
|
||||||
$(SHELL) ./config.status --recheck
|
$(SHELL) ./config.status --recheck
|
||||||
|
|
||||||
shellinaboxd.1: shellinabox/shellinaboxd.man.in
|
shellinaboxd.1: shellinabox/shellinaboxd.man.in $(top_srcdir)/config.h
|
||||||
@src="${top_srcdir}/shellinabox/shellinaboxd.man.in"; \
|
@src="${top_srcdir}/shellinabox/shellinaboxd.man.in"; \
|
||||||
echo preprocess "$$src" '>'"$@"; \
|
echo preprocess "$$src" '>'"$@"; \
|
||||||
if echo " $(DEFS)" | grep HAVE_OPENSSL_BIO_H | \
|
if [ `sed -e 's/^#define \([^ ]*\).*/\1/' -e t -e d \
|
||||||
grep HAVE_OPENSSL_ERR_H | \
|
"${top_srcdir}/config.h" | \
|
||||||
grep -q HAVE_OPENSSL_SSL_H; then \
|
egrep 'HAVE_OPENSSL_BIO_H|HAVE_OPENSSL_ERR_H|HAVE_OPENSSL_SSL_H'|\
|
||||||
|
wc -l` -eq 3 ]; then \
|
||||||
sed -e '/^#ifdef *HAVE_OPENSSL$$/d' \
|
sed -e '/^#ifdef *HAVE_OPENSSL$$/d' \
|
||||||
-e '/^#endif$$/d' "$$src" >"$@"; \
|
-e '/^#endif$$/d' "$$src" >"$@"; \
|
||||||
else \
|
else \
|
||||||
sed -e '/^#ifdef *HAVE_OPENSSL$$/,/^#endif$$/d' "$$src" >"$@"; \
|
sed -e '/^#ifdef *HAVE_OPENSSL$$/,/^#endif$$/d' "$$src" >"$@"; \
|
||||||
|
fi; \
|
||||||
|
if sed -e 's/^#define \([^ ]*\).*/\1/' -e t -e d \
|
||||||
|
"${top_srcdir}/config.h" | \
|
||||||
|
grep 'HAVE_SECURITY_PAM_APPL_H' >/dev/null 2>&1; then \
|
||||||
|
sed -e '/^#ifdef *HAVE_PAM$$/d' \
|
||||||
|
-e '/^#endif$$/d' "$$src" >"$@"; \
|
||||||
|
else \
|
||||||
|
sed -e '/^#ifdef *HAVE_PAM$$/,/^#endif$$/d' "$$src" >"$@"; \
|
||||||
fi
|
fi
|
||||||
@man -Tps "./$@" >`echo "$@" 2>/dev/null|sed -e 's/\.[^.]*$$/.ps/'` \
|
@out=`echo "$@" 2>/dev/null|sed -e 's/\.[^.]*$$/.ps/'`; \
|
||||||
|| true
|
man -Tps "./$@" >"$${out}" 2>/dev/null || rm -f "$${out}"
|
||||||
|
|
||||||
clean-local:
|
clean-local:
|
||||||
-rm -rf shellinaboxd.1 \
|
-rm -rf shellinaboxd.1 \
|
||||||
|
|
21
Makefile.in
21
Makefile.in
|
@ -991,19 +991,28 @@ uninstall-man: uninstall-man1
|
||||||
libtool: $(LIBTOOL_DEPS)
|
libtool: $(LIBTOOL_DEPS)
|
||||||
$(SHELL) ./config.status --recheck
|
$(SHELL) ./config.status --recheck
|
||||||
|
|
||||||
shellinaboxd.1: shellinabox/shellinaboxd.man.in
|
shellinaboxd.1: shellinabox/shellinaboxd.man.in $(top_srcdir)/config.h
|
||||||
@src="${top_srcdir}/shellinabox/shellinaboxd.man.in"; \
|
@src="${top_srcdir}/shellinabox/shellinaboxd.man.in"; \
|
||||||
echo preprocess "$$src" '>'"$@"; \
|
echo preprocess "$$src" '>'"$@"; \
|
||||||
if echo " $(DEFS)" | grep HAVE_OPENSSL_BIO_H | \
|
if [ `sed -e 's/^#define \([^ ]*\).*/\1/' -e t -e d \
|
||||||
grep HAVE_OPENSSL_ERR_H | \
|
"${top_srcdir}/config.h" | \
|
||||||
grep -q HAVE_OPENSSL_SSL_H; then \
|
egrep 'HAVE_OPENSSL_BIO_H|HAVE_OPENSSL_ERR_H|HAVE_OPENSSL_SSL_H'|\
|
||||||
|
wc -l` -eq 3 ]; then \
|
||||||
sed -e '/^#ifdef *HAVE_OPENSSL$$/d' \
|
sed -e '/^#ifdef *HAVE_OPENSSL$$/d' \
|
||||||
-e '/^#endif$$/d' "$$src" >"$@"; \
|
-e '/^#endif$$/d' "$$src" >"$@"; \
|
||||||
else \
|
else \
|
||||||
sed -e '/^#ifdef *HAVE_OPENSSL$$/,/^#endif$$/d' "$$src" >"$@"; \
|
sed -e '/^#ifdef *HAVE_OPENSSL$$/,/^#endif$$/d' "$$src" >"$@"; \
|
||||||
|
fi; \
|
||||||
|
if sed -e 's/^#define \([^ ]*\).*/\1/' -e t -e d \
|
||||||
|
"${top_srcdir}/config.h" | \
|
||||||
|
grep 'HAVE_SECURITY_PAM_APPL_H' >/dev/null 2>&1; then \
|
||||||
|
sed -e '/^#ifdef *HAVE_PAM$$/d' \
|
||||||
|
-e '/^#endif$$/d' "$$src" >"$@"; \
|
||||||
|
else \
|
||||||
|
sed -e '/^#ifdef *HAVE_PAM$$/,/^#endif$$/d' "$$src" >"$@"; \
|
||||||
fi
|
fi
|
||||||
@man -Tps "./$@" >`echo "$@" 2>/dev/null|sed -e 's/\.[^.]*$$/.ps/'` \
|
@out=`echo "$@" 2>/dev/null|sed -e 's/\.[^.]*$$/.ps/'`; \
|
||||||
|| true
|
man -Tps "./$@" >"$${out}" 2>/dev/null || rm -f "$${out}"
|
||||||
|
|
||||||
clean-local:
|
clean-local:
|
||||||
-rm -rf shellinaboxd.1 \
|
-rm -rf shellinaboxd.1 \
|
||||||
|
|
85
configure.ac
85
configure.ac
|
@ -1,5 +1,9 @@
|
||||||
AC_PREREQ(2.57)
|
AC_PREREQ(2.57)
|
||||||
|
|
||||||
|
dnl This is the one location where the authoritative version number is stored
|
||||||
AC_INIT(shellinabox, 2.4, markus@shellinabox.com)
|
AC_INIT(shellinabox, 2.4, markus@shellinabox.com)
|
||||||
|
|
||||||
|
dnl Set up autoconf/automake for building C libraries and binaries with GCC
|
||||||
AM_INIT_AUTOMAKE
|
AM_INIT_AUTOMAKE
|
||||||
AM_CONFIG_HEADER(config.h)
|
AM_CONFIG_HEADER(config.h)
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
|
@ -8,17 +12,17 @@ AC_PROG_LIBTOOL
|
||||||
AC_SUBST(LIBTOOL_DEPS)
|
AC_SUBST(LIBTOOL_DEPS)
|
||||||
AC_C_CONST
|
AC_C_CONST
|
||||||
AC_PROG_GCC_TRADITIONAL
|
AC_PROG_GCC_TRADITIONAL
|
||||||
AC_CHECK_HEADERS([libutil.h openssl/bio.h openssl/err.h openssl/ssl.h \
|
|
||||||
pthread.h security/pam_appl.h security/pam_client.h \
|
dnl Check for header files that do not exist on all platforms
|
||||||
security/pam_misc.h sys/prctrl.h utmp.h utmpx.h])
|
AC_CHECK_HEADERS([libutil.h pthread.h sys/prctrl.h utmp.h utmpx.h])
|
||||||
AC_CHECK_FUNCS(dlopen, [],
|
|
||||||
[AC_CHECK_LIB(dl, dlopen,
|
dnl Most systems require linking against libutil.so in order to get login_tty()
|
||||||
[LIBS="-ldl $LIBS"
|
|
||||||
AC_DEFINE(HAVE_DLOPEN)])])
|
|
||||||
AC_CHECK_FUNCS(login_tty, [],
|
AC_CHECK_FUNCS(login_tty, [],
|
||||||
[AC_CHECK_LIB(util, login_tty,
|
[AC_CHECK_LIB(util, login_tty,
|
||||||
[LIBS="-lutil $LIBS"
|
[LIBS="-lutil $LIBS"
|
||||||
AC_DEFINE(HAVE_LOGIN_TTY)])])
|
AC_DEFINE(HAVE_LOGIN_TTY)])])
|
||||||
|
|
||||||
|
dnl We prefer ptsname_r(), but will settle for ptsname() if necessary
|
||||||
AC_TRY_LINK([#ifndef _XOPEN_SOURCE
|
AC_TRY_LINK([#ifndef _XOPEN_SOURCE
|
||||||
#define _XOPEN_SOURCE
|
#define _XOPEN_SOURCE
|
||||||
#endif
|
#endif
|
||||||
|
@ -29,5 +33,72 @@ AC_TRY_LINK([#ifndef _XOPEN_SOURCE
|
||||||
[ptsname_r(0, 0, 0);],
|
[ptsname_r(0, 0, 0);],
|
||||||
[AC_DEFINE(HAVE_PTSNAME_R, 1,
|
[AC_DEFINE(HAVE_PTSNAME_R, 1,
|
||||||
Define to 1 if you have a re-entrant version of ptsname)])
|
Define to 1 if you have a re-entrant version of ptsname)])
|
||||||
|
|
||||||
|
dnl We automatically detect SSL support, but allow users to disable it
|
||||||
|
AC_ARG_ENABLE(ssl,
|
||||||
|
[ --disable-ssl if available at built-time, support for SSL
|
||||||
|
connections will be enabled. It can still be
|
||||||
|
disabled at run-time, either on the daemon's
|
||||||
|
command line or if the operating system does not
|
||||||
|
have the OpenSSL libraries available.])
|
||||||
|
|
||||||
|
dnl We automatically detect PAM support, but allow users to disable it
|
||||||
|
AC_ARG_ENABLE(pam,
|
||||||
|
[ --disable-pam PAM support is necessary in order to authenticate
|
||||||
|
users for running programs other than their default
|
||||||
|
login shell.])
|
||||||
|
|
||||||
|
dnl We try to always use dlopen() instead of linking libraries dynamically, as
|
||||||
|
dnl this reduces the hard run-time dependencies that our binary has. But we
|
||||||
|
dnl allow users to disable this feature.
|
||||||
|
AC_ARG_ENABLE(runtime-loading,
|
||||||
|
[ --disable-runtime-loading ShellInABox will try to load the OpenSSL, and PAM
|
||||||
|
libraries at run-time, if it has been compiled with
|
||||||
|
support for these libraries, and if the operating
|
||||||
|
system supports dynamic loading of libraries. This
|
||||||
|
allows you to install the same binary on different
|
||||||
|
systems independent of whether they have OpenSSL
|
||||||
|
and PAM enabled. If you would rather directly link
|
||||||
|
these libraries into the binary, thus making them a
|
||||||
|
hard dependency, then disable runtime-loading.])
|
||||||
|
|
||||||
|
dnl Only test for OpenSSL headers, if not explicitly disabled
|
||||||
|
if test "x$enable_ssl" != xno; then
|
||||||
|
AC_CHECK_HEADERS([openssl/bio.h openssl/err.h openssl/ssl.h])
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl Only test for PAM headers, if not explicitly disabled
|
||||||
|
if test "x$enable_pam" != xno; then
|
||||||
|
AC_CHECK_HEADERS([security/pam_appl.h security/pam_client.h \
|
||||||
|
security/pam_misc.h ])
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl Only test for dlopen(), if not explicitly disabled. Add required libdl.so
|
||||||
|
dnl library if necessary. Also, if dlopen() is not available on this system,
|
||||||
|
dnl explicitly disable runtime loading.
|
||||||
|
if test "x$enable_runtime_loading" != xno; then
|
||||||
|
AC_CHECK_FUNCS(dlopen, [],
|
||||||
|
[AC_CHECK_LIB(dl, dlopen,
|
||||||
|
[LIBS="-ldl $LIBS"
|
||||||
|
AC_DEFINE(HAVE_DLOPEN)],
|
||||||
|
[enable_runtime_loading=no])])
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl If runtime loading has been disabled, add OpenSSL and PAM as hard
|
||||||
|
dnl dependencies.
|
||||||
|
if test "x$enable_runtime_loading" == xno; then
|
||||||
|
dnl Link against OpenSSL libraries, unless SSL support has been disabled
|
||||||
|
if test "x$enable_ssl" != xno; then
|
||||||
|
AC_CHECK_HEADER(openssl/ssl.h, [LIBS="-lssl $LIBS"])
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl Link against PAM libraries, unless PAM support has been disabled
|
||||||
|
if test "x$enable_pam" != xno; then
|
||||||
|
AC_CHECK_HEADER(security/pam_appl.h, [LIBS="-lpam $LIBS"])
|
||||||
|
AC_CHECK_HEADER(security/pam_misc.h, [LIBS="-lpam_misc $LIBS"])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl Generate output files
|
||||||
AC_CONFIG_FILES([Makefile])
|
AC_CONFIG_FILES([Makefile])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
|
@ -67,12 +67,15 @@
|
||||||
// Pthread support is optional. Only enable it, if the library has been
|
// Pthread support is optional. Only enable it, if the library has been
|
||||||
// linked into the program
|
// linked into the program
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#if defined(__linux__)
|
||||||
extern int pthread_once(pthread_once_t *, void (*)(void))__attribute__((weak));
|
extern int pthread_once(pthread_once_t *, void (*)(void))__attribute__((weak));
|
||||||
|
#endif
|
||||||
extern int pthread_sigmask(int, const sigset_t *, sigset_t *)
|
extern int pthread_sigmask(int, const sigset_t *, sigset_t *)
|
||||||
__attribute__((weak));
|
__attribute__((weak));
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_DLOPEN)
|
||||||
// SSL support is optional. Only enable it, if the library can be loaded.
|
// SSL support is optional. Only enable it, if the library can be loaded.
|
||||||
long (*BIO_ctrl)(BIO *, int, long, void *);
|
long (*BIO_ctrl)(BIO *, int, long, void *);
|
||||||
BIO_METHOD * (*BIO_f_buffer)(void);
|
BIO_METHOD * (*BIO_f_buffer)(void);
|
||||||
|
@ -113,7 +116,7 @@ int (*SSL_set_ex_data)(SSL *, int, void *);
|
||||||
int (*SSL_shutdown)(SSL *);
|
int (*SSL_shutdown)(SSL *);
|
||||||
int (*SSL_write)(SSL *, const void *, int);
|
int (*SSL_write)(SSL *, const void *, int);
|
||||||
SSL_METHOD * (*SSLv23_server_method)(void);
|
SSL_METHOD * (*SSLv23_server_method)(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
static void sslDestroyCachedContext(void *ssl_, char *context_) {
|
static void sslDestroyCachedContext(void *ssl_, char *context_) {
|
||||||
struct SSLSupport *ssl = (struct SSLSupport *)ssl_;
|
struct SSLSupport *ssl = (struct SSLSupport *)ssl_;
|
||||||
|
@ -163,7 +166,7 @@ void deleteSSL(struct SSLSupport *ssl) {
|
||||||
free(ssl);
|
free(ssl);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_OPENSSL)
|
#if defined(HAVE_OPENSSL) && defined(HAVE_DLOPEN)
|
||||||
static void *loadSymbol(const char *lib, const char *fn) {
|
static void *loadSymbol(const char *lib, const char *fn) {
|
||||||
void *dl = RTLD_DEFAULT;
|
void *dl = RTLD_DEFAULT;
|
||||||
void *rc = dlsym(dl, fn);
|
void *rc = dlsym(dl, fn);
|
||||||
|
@ -251,6 +254,9 @@ static void loadSSL(void) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int serverSupportsSSL(void) {
|
int serverSupportsSSL(void) {
|
||||||
|
#if defined(HAVE_OPENSSL) && !defined(HAVE_DLOPEN)
|
||||||
|
return SSL_library_init();
|
||||||
|
#else
|
||||||
#if defined(HAVE_OPENSSL)
|
#if defined(HAVE_OPENSSL)
|
||||||
// We want to call loadSSL() exactly once. For single-threaded applications,
|
// We want to call loadSSL() exactly once. For single-threaded applications,
|
||||||
// this is straight-forward. For threaded applications, we need to call
|
// this is straight-forward. For threaded applications, we need to call
|
||||||
|
@ -274,6 +280,7 @@ int serverSupportsSSL(void) {
|
||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_OPENSSL)
|
#if defined(HAVE_OPENSSL)
|
||||||
|
|
|
@ -68,6 +68,7 @@ typedef struct SSL_METHOD SSL_METHOD;
|
||||||
#define SSL_ERROR_WANT_WRITE 3
|
#define SSL_ERROR_WANT_WRITE 3
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_DLOPEN)
|
||||||
extern long (*x_BIO_ctrl)(BIO *, int, long, void *);
|
extern long (*x_BIO_ctrl)(BIO *, int, long, void *);
|
||||||
extern BIO_METHOD *(*x_BIO_f_buffer)(void);
|
extern BIO_METHOD *(*x_BIO_f_buffer)(void);
|
||||||
extern void (*x_BIO_free_all)(BIO *);
|
extern void (*x_BIO_free_all)(BIO *);
|
||||||
|
@ -166,6 +167,7 @@ extern SSL_METHOD *(*x_SSLv23_server_method)(void);
|
||||||
#define SSL_get_app_data(s) (x_SSL_get_ex_data(s, 0))
|
#define SSL_get_app_data(s) (x_SSL_get_ex_data(s, 0))
|
||||||
#define SSL_set_app_data(s, arg) (x_SSL_set_ex_data(s, 0, (char *)arg))
|
#define SSL_set_app_data(s, arg) (x_SSL_set_ex_data(s, 0, (char *)arg))
|
||||||
#define SSL_set_mode(ssl, op) (x_SSL_ctrl((ssl), SSL_CTRL_MODE, (op), NULL))
|
#define SSL_set_mode(ssl, op) (x_SSL_ctrl((ssl), SSL_CTRL_MODE, (op), NULL))
|
||||||
|
#endif
|
||||||
|
|
||||||
struct SSLSupport {
|
struct SSLSupport {
|
||||||
int enabled;
|
int enabled;
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -90,7 +91,7 @@ struct pam_conv;
|
||||||
typedef struct pam_handle pam_handle_t;
|
typedef struct pam_handle pam_handle_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_PTHREAD_H)
|
#if defined(HAVE_PTHREAD_H) && defined(__linux__)
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
extern int pthread_once(pthread_once_t *, void (*)(void))__attribute__((weak));
|
extern int pthread_once(pthread_once_t *, void (*)(void))__attribute__((weak));
|
||||||
#endif
|
#endif
|
||||||
|
@ -103,7 +104,7 @@ extern int pthread_once(pthread_once_t *, void (*)(void))__attribute__((weak));
|
||||||
|
|
||||||
// If PAM support is available, take advantage of it. Otherwise, silently fall
|
// If PAM support is available, take advantage of it. Otherwise, silently fall
|
||||||
// back on legacy operations for session management.
|
// back on legacy operations for session management.
|
||||||
#if defined(HAVE_SECURITY_PAM_APPL_H)
|
#if defined(HAVE_SECURITY_PAM_APPL_H) && defined(HAVE_DLOPEN)
|
||||||
static int (*x_pam_acct_mgmt)(pam_handle_t *, int);
|
static int (*x_pam_acct_mgmt)(pam_handle_t *, int);
|
||||||
static int (*x_pam_authenticate)(pam_handle_t *, int);
|
static int (*x_pam_authenticate)(pam_handle_t *, int);
|
||||||
#if defined(HAVE_SECURITY_PAM_CLIENT_H)
|
#if defined(HAVE_SECURITY_PAM_CLIENT_H)
|
||||||
|
@ -118,6 +119,17 @@ static int (*x_pam_start)(const char *, const char *, const struct pam_conv *,
|
||||||
pam_handle_t **);
|
pam_handle_t **);
|
||||||
static int (*x_misc_conv)(int, const struct pam_message **,
|
static int (*x_misc_conv)(int, const struct pam_message **,
|
||||||
struct pam_response **, void *);
|
struct pam_response **, void *);
|
||||||
|
|
||||||
|
#define pam_acct_mgmt x_pam_acct_mgmt
|
||||||
|
#define pam_authenticate x_pam_authenticate
|
||||||
|
#define pam_binary_handler_fn x_pam_binary_handler_fn
|
||||||
|
#define pam_close_session x_pam_close_session
|
||||||
|
#define pam_end x_pam_end
|
||||||
|
#define pam_get_item x_pam_get_item
|
||||||
|
#define pam_open_session x_pam_open_session
|
||||||
|
#define pam_set_item x_pam_set_item
|
||||||
|
#define pam_start x_pam_start
|
||||||
|
#define misc_conv x_misc_conv
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Older versions of glibc might not support fdopendir(). That's OK, we can
|
// Older versions of glibc might not support fdopendir(). That's OK, we can
|
||||||
|
@ -128,7 +140,7 @@ static int launcher = -1;
|
||||||
static uid_t restricted;
|
static uid_t restricted;
|
||||||
|
|
||||||
|
|
||||||
#if defined(HAVE_SECURITY_PAM_APPL_H)
|
#if defined(HAVE_SECURITY_PAM_APPL_H) && defined(HAVE_DLOPEN)
|
||||||
|
|
||||||
// If the PAM misc library cannot be found, we have to provide our own basic
|
// If the PAM misc library cannot be found, we have to provide our own basic
|
||||||
// conversation function. As we know that this code is only ever called from
|
// conversation function. As we know that this code is only ever called from
|
||||||
|
@ -221,14 +233,14 @@ static int my_misc_conv(int num_msg, const struct pam_message **msgm,
|
||||||
#if defined(HAVE_SECURITY_PAM_CLIENT_H)
|
#if defined(HAVE_SECURITY_PAM_CLIENT_H)
|
||||||
case PAM_BINARY_PROMPT: {
|
case PAM_BINARY_PROMPT: {
|
||||||
pamc_bp_t binary_prompt = NULL;
|
pamc_bp_t binary_prompt = NULL;
|
||||||
if (!msgm[count]->msg || !*x_pam_binary_handler_fn) {
|
if (!msgm[count]->msg || !*pam_binary_handler_fn) {
|
||||||
goto failed_conversation;
|
goto failed_conversation;
|
||||||
}
|
}
|
||||||
PAM_BP_RENEW(p(&binary_prompt), PAM_BP_RCONTROL(msgm[count]->msg),
|
PAM_BP_RENEW(p(&binary_prompt), PAM_BP_RCONTROL(msgm[count]->msg),
|
||||||
PAM_BP_LENGTH(msgm[count]->msg));
|
PAM_BP_LENGTH(msgm[count]->msg));
|
||||||
PAM_BP_FILL(binary_prompt, 0, PAM_BP_LENGTH(msgm[count]->msg),
|
PAM_BP_FILL(binary_prompt, 0, PAM_BP_LENGTH(msgm[count]->msg),
|
||||||
PAM_BP_RDATA(msgm[count]->msg));
|
PAM_BP_RDATA(msgm[count]->msg));
|
||||||
if ((*x_pam_binary_handler_fn)(appdata_ptr, &binary_prompt) !=
|
if ((*pam_binary_handler_fn)(appdata_ptr, &binary_prompt) !=
|
||||||
PAM_SUCCESS || !binary_prompt) {
|
PAM_SUCCESS || !binary_prompt) {
|
||||||
goto failed_conversation;
|
goto failed_conversation;
|
||||||
}
|
}
|
||||||
|
@ -268,8 +280,8 @@ static void *loadSymbol(const char *lib, const char *fn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loadPAM(void) {
|
static void loadPAM(void) {
|
||||||
check(!x_pam_start);
|
check(!pam_start);
|
||||||
check(!x_misc_conv);
|
check(!misc_conv);
|
||||||
struct {
|
struct {
|
||||||
union {
|
union {
|
||||||
void *avoid_gcc_warning_about_type_punning;
|
void *avoid_gcc_warning_about_type_punning;
|
||||||
|
@ -278,18 +290,18 @@ static void loadPAM(void) {
|
||||||
const char *lib;
|
const char *lib;
|
||||||
const char *fn;
|
const char *fn;
|
||||||
} symbols[] = {
|
} symbols[] = {
|
||||||
{ { &x_pam_acct_mgmt }, "libpam.so", "pam_acct_mgmt" },
|
{ { &pam_acct_mgmt }, "libpam.so", "pam_acct_mgmt" },
|
||||||
{ { &x_pam_authenticate }, "libpam.so", "pam_authenticate" },
|
{ { &pam_authenticate }, "libpam.so", "pam_authenticate" },
|
||||||
#if defined(HAVE_SECURITY_PAM_CLIENT_H)
|
#if defined(HAVE_SECURITY_PAM_CLIENT_H)
|
||||||
{ { &x_pam_binary_handler_fn }, "libpam_misc.so", "pam_binary_handler_fn"},
|
{ { &pam_binary_handler_fn }, "libpam_misc.so", "pam_binary_handler_fn" },
|
||||||
#endif
|
#endif
|
||||||
{ { &x_pam_close_session }, "libpam.so", "pam_close_session" },
|
{ { &pam_close_session }, "libpam.so", "pam_close_session" },
|
||||||
{ { &x_pam_end }, "libpam.so", "pam_end" },
|
{ { &pam_end }, "libpam.so", "pam_end" },
|
||||||
{ { &x_pam_get_item }, "libpam.so", "pam_get_item" },
|
{ { &pam_get_item }, "libpam.so", "pam_get_item" },
|
||||||
{ { &x_pam_open_session }, "libpam.so", "pam_open_session" },
|
{ { &pam_open_session }, "libpam.so", "pam_open_session" },
|
||||||
{ { &x_pam_set_item }, "libpam.so", "pam_set_item" },
|
{ { &pam_set_item }, "libpam.so", "pam_set_item" },
|
||||||
{ { &x_pam_start }, "libpam.so", "pam_start" },
|
{ { &pam_start }, "libpam.so", "pam_start" },
|
||||||
{ { &x_misc_conv }, "libpam_misc.so", "misc_conv" }
|
{ { &misc_conv }, "libpam_misc.so", "misc_conv" }
|
||||||
};
|
};
|
||||||
for (int i = 0; i < sizeof(symbols)/sizeof(symbols[0]); i++) {
|
for (int i = 0; i < sizeof(symbols)/sizeof(symbols[0]); i++) {
|
||||||
if (!(*symbols[i].var = loadSymbol(symbols[i].lib, symbols[i].fn))) {
|
if (!(*symbols[i].var = loadSymbol(symbols[i].lib, symbols[i].fn))) {
|
||||||
|
@ -317,6 +329,9 @@ static void loadPAM(void) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int supportsPAM(void) {
|
int supportsPAM(void) {
|
||||||
|
#if defined(HAVE_SECURITY_PAM_APPL_H) && !defined(HAVE_DLOPEN)
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
#if defined(HAVE_SECURITY_PAM_APPL_H)
|
#if defined(HAVE_SECURITY_PAM_APPL_H)
|
||||||
|
|
||||||
// We want to call loadPAM() exactly once. For single-threaded applications,
|
// We want to call loadPAM() exactly once. For single-threaded applications,
|
||||||
|
@ -337,10 +352,11 @@ int supportsPAM(void) {
|
||||||
loadPAM();
|
loadPAM();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return x_misc_conv && x_pam_start;
|
return misc_conv && pam_start;
|
||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int launchChild(int service, struct Session *session) {
|
int launchChild(int service, struct Session *session) {
|
||||||
|
@ -540,7 +556,7 @@ static int ptsname_r(int fd, char *buf, size_t buflen) {
|
||||||
}
|
}
|
||||||
strcpy(buf, p);
|
strcpy(buf, p);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int forkPty(int *pty, int useLogin, struct Utmp **utmp,
|
static int forkPty(int *pty, int useLogin, struct Utmp **utmp,
|
||||||
|
@ -666,48 +682,48 @@ static pam_handle_t *internalLogin(struct Service *service, struct Utmp *utmp,
|
||||||
const struct passwd *pw;
|
const struct passwd *pw;
|
||||||
pam_handle_t *pam = NULL;
|
pam_handle_t *pam = NULL;
|
||||||
#if defined(HAVE_SECURITY_PAM_APPL_H)
|
#if defined(HAVE_SECURITY_PAM_APPL_H)
|
||||||
struct pam_conv conv = { .conv = x_misc_conv };
|
struct pam_conv conv = { .conv = misc_conv };
|
||||||
if (service->authUser) {
|
if (service->authUser) {
|
||||||
check(supportsPAM());
|
check(supportsPAM());
|
||||||
check(x_pam_start("shellinabox", NULL, &conv, &pam) == PAM_SUCCESS);
|
check(pam_start("shellinabox", NULL, &conv, &pam) == PAM_SUCCESS);
|
||||||
|
|
||||||
// Change the prompt to include the host name
|
// Change the prompt to include the host name
|
||||||
struct utsname uts;
|
struct utsname uts;
|
||||||
check(!uname(&uts));
|
check(!uname(&uts));
|
||||||
const char *origPrompt;
|
const char *origPrompt;
|
||||||
check(x_pam_get_item(pam, PAM_USER_PROMPT, (void *)&origPrompt) ==
|
check(pam_get_item(pam, PAM_USER_PROMPT, (void *)&origPrompt) ==
|
||||||
PAM_SUCCESS);
|
PAM_SUCCESS);
|
||||||
char *prompt;
|
char *prompt;
|
||||||
check(prompt = stringPrintf(NULL, "%s %s", uts.nodename,
|
check(prompt = stringPrintf(NULL, "%s %s", uts.nodename,
|
||||||
origPrompt ? origPrompt : "login: "));
|
origPrompt ? origPrompt : "login: "));
|
||||||
check(x_pam_set_item(pam, PAM_USER_PROMPT, prompt) == PAM_SUCCESS);
|
check(pam_set_item(pam, PAM_USER_PROMPT, prompt) == PAM_SUCCESS);
|
||||||
|
|
||||||
// Up to three attempts to enter the user id and password
|
// Up to three attempts to enter the user id and password
|
||||||
for (int i = 0;;) {
|
for (int i = 0;;) {
|
||||||
check(x_pam_set_item(pam, PAM_USER, NULL) == PAM_SUCCESS);
|
check(pam_set_item(pam, PAM_USER, NULL) == PAM_SUCCESS);
|
||||||
int rc;
|
int rc;
|
||||||
if ((rc = x_pam_authenticate(pam, PAM_SILENT)) ==
|
if ((rc = pam_authenticate(pam, PAM_SILENT)) ==
|
||||||
PAM_SUCCESS &&
|
PAM_SUCCESS &&
|
||||||
(geteuid() ||
|
(geteuid() ||
|
||||||
(rc = x_pam_acct_mgmt(pam, PAM_SILENT)) ==
|
(rc = pam_acct_mgmt(pam, PAM_SILENT)) ==
|
||||||
PAM_SUCCESS)) {
|
PAM_SUCCESS)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (++i == 3) {
|
if (++i == 3) {
|
||||||
// Quit if login failed.
|
// Quit if login failed.
|
||||||
puts("\nMaximum number of tries exceeded (3)");
|
puts("\nMaximum number of tries exceeded (3)");
|
||||||
x_pam_end(pam, rc);
|
pam_end(pam, rc);
|
||||||
_exit(1);
|
_exit(1);
|
||||||
} else {
|
} else {
|
||||||
puts("\nLogin incorrect");
|
puts("\nLogin incorrect");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
check(x_pam_set_item(pam, PAM_USER_PROMPT, "login: ") == PAM_SUCCESS);
|
check(pam_set_item(pam, PAM_USER_PROMPT, "login: ") == PAM_SUCCESS);
|
||||||
free(prompt);
|
free(prompt);
|
||||||
|
|
||||||
// Retrieve user id, and group id.
|
// Retrieve user id, and group id.
|
||||||
const char *name;
|
const char *name;
|
||||||
check(x_pam_get_item(pam, PAM_USER, (void *)&name) == PAM_SUCCESS);
|
check(pam_get_item(pam, PAM_USER, (void *)&name) == PAM_SUCCESS);
|
||||||
pw = getPWEnt(getUserId(name));
|
pw = getPWEnt(getUserId(name));
|
||||||
check(service->uid < 0);
|
check(service->uid < 0);
|
||||||
check(service->gid < 0);
|
check(service->gid < 0);
|
||||||
|
@ -723,16 +739,16 @@ static pam_handle_t *internalLogin(struct Service *service, struct Utmp *utmp,
|
||||||
check(service->user);
|
check(service->user);
|
||||||
check(service->group);
|
check(service->group);
|
||||||
if (supportsPAM()) {
|
if (supportsPAM()) {
|
||||||
check(x_pam_start("shellinabox", service->user, &conv, &pam) ==
|
check(pam_start("shellinabox", service->user, &conv, &pam) ==
|
||||||
PAM_SUCCESS);
|
PAM_SUCCESS);
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
// PAM account management requires root access. Just skip it, if we
|
// PAM account management requires root access. Just skip it, if we
|
||||||
// are running with lower privileges.
|
// are running with lower privileges.
|
||||||
if (geteuid() &&
|
if (geteuid() &&
|
||||||
(rc = x_pam_acct_mgmt(pam, PAM_SILENT)) !=
|
(rc = pam_acct_mgmt(pam, PAM_SILENT)) !=
|
||||||
PAM_SUCCESS) {
|
PAM_SUCCESS) {
|
||||||
x_pam_end(pam, rc);
|
pam_end(pam, rc);
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -747,7 +763,7 @@ static pam_handle_t *internalLogin(struct Service *service, struct Utmp *utmp,
|
||||||
(service->uid != restricted || service->gid != pw->pw_gid)) {
|
(service->uid != restricted || service->gid != pw->pw_gid)) {
|
||||||
puts("\nAccess denied!");
|
puts("\nAccess denied!");
|
||||||
#if defined(HAVE_SECURITY_PAM_APPL_H)
|
#if defined(HAVE_SECURITY_PAM_APPL_H)
|
||||||
x_pam_end(pam, PAM_SUCCESS);
|
pam_end(pam, PAM_SUCCESS);
|
||||||
#endif
|
#endif
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
@ -755,7 +771,7 @@ static pam_handle_t *internalLogin(struct Service *service, struct Utmp *utmp,
|
||||||
#if defined(HAVE_SECURITY_PAM_APPL_H)
|
#if defined(HAVE_SECURITY_PAM_APPL_H)
|
||||||
if (pam) {
|
if (pam) {
|
||||||
#ifdef HAVE_UTMPX_H
|
#ifdef HAVE_UTMPX_H
|
||||||
check(x_pam_set_item(pam, PAM_TTY, (const void **)utmp->utmpx.ut_line) ==
|
check(pam_set_item(pam, PAM_TTY, (const void **)utmp->utmpx.ut_line) ==
|
||||||
PAM_SUCCESS);
|
PAM_SUCCESS);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -1080,7 +1096,7 @@ static void childProcess(struct Service *service, int width, int height,
|
||||||
pam_handle_t *pam = internalLogin(service, utmp, &environment);
|
pam_handle_t *pam = internalLogin(service, utmp, &environment);
|
||||||
#if defined(HAVE_SECURITY_PAM_APPL_H)
|
#if defined(HAVE_SECURITY_PAM_APPL_H)
|
||||||
if (pam && !geteuid()) {
|
if (pam && !geteuid()) {
|
||||||
check(x_pam_open_session(pam, PAM_SILENT) == PAM_SUCCESS);
|
check(pam_open_session(pam, PAM_SILENT) == PAM_SUCCESS);
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
switch (pid) {
|
switch (pid) {
|
||||||
case -1:
|
case -1:
|
||||||
|
@ -1091,9 +1107,9 @@ static void childProcess(struct Service *service, int width, int height,
|
||||||
// Finish all pending PAM operations.
|
// Finish all pending PAM operations.
|
||||||
int status, rc;
|
int status, rc;
|
||||||
check(NOINTR(waitpid(pid, &status, 0)) == pid);
|
check(NOINTR(waitpid(pid, &status, 0)) == pid);
|
||||||
check((rc = x_pam_close_session(pam, PAM_SILENT)) ==
|
check((rc = pam_close_session(pam, PAM_SILENT)) ==
|
||||||
PAM_SUCCESS);
|
PAM_SUCCESS);
|
||||||
check(x_pam_end(pam, rc) == PAM_SUCCESS);
|
check(pam_end(pam, rc) == PAM_SUCCESS);
|
||||||
_exit(WIFEXITED(status) ? WEXITSTATUS(status) : -WTERMSIG(status));
|
_exit(WIFEXITED(status) ? WEXITSTATUS(status) : -WTERMSIG(status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -300,13 +300,19 @@ Alternatively, an \fIapplication\fP can be specified by providing a
|
||||||
\fIuser\fP description, a working directory, and a command line:
|
\fIuser\fP description, a working directory, and a command line:
|
||||||
.in +4
|
.in +4
|
||||||
\fIAPPLICATION\fP := 'LOGIN' | \fIUSER\fP ':' \fICWD\fP ':' <cmdline>
|
\fIAPPLICATION\fP := 'LOGIN' | \fIUSER\fP ':' \fICWD\fP ':' <cmdline>
|
||||||
.in
|
|
||||||
|
|
||||||
|
#ifdef HAVE_PAM
|
||||||
|
.in
|
||||||
The keyword 'AUTH' indicates that the \fIuser\fP information should
|
The keyword 'AUTH' indicates that the \fIuser\fP information should
|
||||||
be requested interactively, instead of being provided as part of the
|
be requested interactively, instead of being provided as part of the
|
||||||
\fIservice\fP description:
|
\fIservice\fP description:
|
||||||
.in +4
|
.in +4
|
||||||
\fIUSER\fP := 'AUTH' | <username> ':' <groupname>
|
#endif
|
||||||
|
\fIUSER\fP :=
|
||||||
|
#ifdef HAVE_PAM
|
||||||
|
'AUTH' |
|
||||||
|
#endif
|
||||||
|
<username> ':' <groupname>
|
||||||
.in
|
.in
|
||||||
|
|
||||||
The working directory can either be given as an absolute path, or it
|
The working directory can either be given as an absolute path, or it
|
||||||
|
|
Loading…
Reference in a new issue