Feature #688 » 0002-pam-auth.patch
configure.ac | ||
---|---|---|
fi
|
||
AM_CONDITIONAL(BUILD_WITH_LDAP, test ! $WITH_LDAP = no)
|
||
dnl Check for PAM
|
||
AC_MSG_CHECKING(for PAM support)
|
||
AC_ARG_WITH(pam, AC_HELP_STRING([--with-pam],[enable PAM support]),
|
||
[WITH_PAM=$withval], [WITH_PAM=no])
|
||
AC_MSG_RESULT([$withval])
|
||
if test "$WITH_PAM" != "no"; then
|
||
AC_CHECK_LIB(pam, pam_start, [
|
||
AC_CHECK_HEADERS([security/pam_appl.h],[
|
||
PAM_LIB=-lpam
|
||
AC_DEFINE([HAVE_LIBPAM], [1], [libpam])
|
||
AC_DEFINE([HAVE_SECURITY_PAM_APPL_H], [1])
|
||
])
|
||
])
|
||
AC_SUBST(PAM_LIB)
|
||
fi
|
||
AM_CONDITIONAL(BUILD_WITH_PAM, test ! $WITH_PAM = no)
|
||
dnl Check for xattr
|
||
AC_MSG_CHECKING(for extended attributes support)
|
||
AC_ARG_WITH(attr, AC_HELP_STRING([--with-attr],[enable extended attribute support]),
|
||
... | ... | |
no_build="$no_build $plugins"
|
||
fi
|
||
plugins="mod_authn_pam"
|
||
if test ! "x$PAM_LIB" = x; then
|
||
do_build="$do_build $plugins"
|
||
else
|
||
no_build="$no_build $plugins"
|
||
fi
|
||
features="network-openssl"
|
||
if test ! "x$SSL_LIB" = x; then
|
||
enable_feature="$enable_feature $features"
|
src/Makefile.am | ||
---|---|---|
mod_authn_ldap_la_LIBADD = $(LDAP_LIB) $(LBER_LIB) $(common_libadd)
|
||
endif
|
||
if BUILD_WITH_PAM
|
||
lib_LTLIBRARIES += mod_authn_pam.la
|
||
mod_authn_pam_la_SOURCES = mod_authn_pam.c
|
||
mod_authn_pam_la_LDFLAGS = $(common_module_ldflags)
|
||
mod_authn_pam_la_LIBADD = $(PAM_LIB) $(common_libadd)
|
||
endif
|
||
if BUILD_WITH_MYSQL
|
||
lib_LTLIBRARIES += mod_authn_mysql.la
|
||
mod_authn_mysql_la_SOURCES = mod_authn_mysql.c
|
src/configfile.c | ||
---|---|---|
#include <glob.h>
|
||
#if defined(HAVE_MYSQL) || (defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER))
|
||
#if defined(HAVE_LIBPAM) || defined(HAVE_MYSQL) || (defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER))
|
||
static void config_warn_authn_module (server *srv, const char *module) {
|
||
size_t len = strlen(module);
|
||
for (size_t i = 0; i < srv->config_context->used; ++i) {
|
||
... | ... | |
int append_mod_authn_file = 1;
|
||
int append_mod_authn_ldap = 1;
|
||
int append_mod_authn_mysql = 1;
|
||
int append_mod_authn_pam = 1;
|
||
int contains_mod_auth = 0;
|
||
/* prepend default modules */
|
||
... | ... | |
append_mod_authn_mysql = 0;
|
||
}
|
||
if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_authn_pam"))) {
|
||
append_mod_authn_pam = 0;
|
||
}
|
||
if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_auth"))) {
|
||
contains_mod_auth = 1;
|
||
}
|
||
... | ... | |
0 == append_mod_authn_file &&
|
||
0 == append_mod_authn_ldap &&
|
||
0 == append_mod_authn_mysql &&
|
||
0 == append_mod_authn_pam &&
|
||
1 == contains_mod_auth) {
|
||
break;
|
||
}
|
src/mod_authn_pam.c | ||
---|---|---|
#include "first.h"
|
||
#define USE_PAM
|
||
#include <security/pam_appl.h>
|
||
#include "server.h"
|
||
#include "http_auth.h"
|
||
#include "log.h"
|
||
#include "plugin.h"
|
||
#include <errno.h>
|
||
#include <string.h>
|
||
typedef struct {
|
||
buffer *auth_pam_servicename;
|
||
} plugin_config;
|
||
typedef struct {
|
||
PLUGIN_DATA;
|
||
plugin_config **config_storage;
|
||
plugin_config conf, *anon_conf; /* this is only used as long as no handler_ctx is setup */
|
||
} plugin_data;
|
||
static handler_t mod_authn_pam_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw);
|
||
INIT_FUNC(mod_authn_pam_init) {
|
||
static http_auth_backend_t http_auth_backend_pam =
|
||
{ "pam", mod_authn_pam_basic, NULL, NULL };
|
||
plugin_data *p = calloc(1, sizeof(*p));
|
||
/* register http_auth_backend_pam */
|
||
http_auth_backend_pam.p_d = p;
|
||
http_auth_backend_set(&http_auth_backend_pam);
|
||
return p;
|
||
}
|
||
FREE_FUNC(mod_authn_pam_free) {
|
||
plugin_data *p = p_d;
|
||
UNUSED(srv);
|
||
if (!p) return HANDLER_GO_ON;
|
||
if (p->config_storage) {
|
||
size_t i;
|
||
for (i = 0; i < srv->config_context->used; i++) {
|
||
plugin_config *s = p->config_storage[i];
|
||
if (NULL == s) continue;
|
||
buffer_free(s->auth_pam_servicename);
|
||
free(s);
|
||
}
|
||
free(p->config_storage);
|
||
}
|
||
free(p);
|
||
return HANDLER_GO_ON;
|
||
}
|
||
SETDEFAULTS_FUNC(mod_authn_pam_set_defaults) {
|
||
plugin_data *p = p_d;
|
||
size_t i;
|
||
config_values_t cv[] = {
|
||
{ "auth.backend.pam.service-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
|
||
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
|
||
};
|
||
p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
|
||
for (i = 0; i < srv->config_context->used; i++) {
|
||
data_config const* config = (data_config const*)srv->config_context->data[i];
|
||
plugin_config *s;
|
||
s = calloc(1, sizeof(plugin_config));
|
||
s->auth_pam_servicename = buffer_init();
|
||
cv[0].destination = s->auth_pam_servicename;
|
||
p->config_storage[i] = s;
|
||
if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
|
||
return HANDLER_ERROR;
|
||
}
|
||
}
|
||
return HANDLER_GO_ON;
|
||
}
|
||
#define PATCH(x) \
|
||
p->conf.x = s->x;
|
||
static int mod_authn_pam_patch_connection(server *srv, connection *con, plugin_data *p) {
|
||
size_t i, j;
|
||
plugin_config *s = p->config_storage[0];
|
||
PATCH(auth_pam_servicename);
|
||
/* skip the first, the global context */
|
||
for (i = 1; i < srv->config_context->used; i++) {
|
||
data_config *dc = (data_config *)srv->config_context->data[i];
|
||
s = p->config_storage[i];
|
||
/* condition didn't match */
|
||
if (!config_check_cond(srv, con, dc)) continue;
|
||
/* merge config */
|
||
for (j = 0; j < dc->value->used; j++) {
|
||
data_unset *du = dc->value->data[j];
|
||
if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.pam.service-name"))) {
|
||
PATCH(auth_pam_servicename);
|
||
}
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
#undef PATCH
|
||
typedef struct {
|
||
plugin_config *conf;
|
||
const char *username;
|
||
const char *realm;
|
||
const char *password;
|
||
} mod_auth_pam_data;
|
||
static int mod_authn_pam_fn_conv(int num_msg, const struct pam_message **msg, struct pam_response **p_resp, void *appdata_ptr) {
|
||
mod_auth_pam_data *p_pam = (mod_auth_pam_data *)appdata_ptr;
|
||
struct pam_response *resp = (struct pam_response *)malloc(num_msg * sizeof(struct pam_response));
|
||
for(int i = 0; i < num_msg; ++i) {
|
||
switch(msg[i]->msg_style) {
|
||
case PAM_PROMPT_ECHO_OFF:
|
||
case PAM_PROMPT_ECHO_ON:
|
||
resp[i].resp = strdup(p_pam->password);
|
||
resp[i].resp_retcode = 0;
|
||
break;
|
||
case PAM_ERROR_MSG:
|
||
case PAM_TEXT_INFO:
|
||
default:
|
||
// ignore
|
||
resp[i].resp_retcode = 0;
|
||
resp[i].resp = NULL;
|
||
continue;
|
||
}
|
||
}
|
||
*p_resp = resp;
|
||
return PAM_SUCCESS;
|
||
}
|
||
static handler_t mod_authn_pam_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw) {
|
||
plugin_data *p = (plugin_data *)p_d;
|
||
pam_handle_t *pamh = NULL;
|
||
mod_auth_pam_data pam_data = {
|
||
&p->conf,
|
||
username->ptr,
|
||
require->realm->ptr,
|
||
pw
|
||
};
|
||
struct pam_conv conv = { mod_authn_pam_fn_conv, &pam_data };
|
||
|
||
mod_authn_pam_patch_connection(srv, con, p);
|
||
int retval = pam_start(
|
||
!buffer_is_empty(p->conf.auth_pam_servicename) ? p->conf.auth_pam_servicename->ptr : "lighttpd",
|
||
username->ptr,
|
||
&conv,
|
||
&pamh);
|
||
if(retval != PAM_SUCCESS)
|
||
goto auth_pam_fail;
|
||
if((retval = pam_authenticate(pamh, PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS)
|
||
goto auth_pam_fail;
|
||
if((retval = pam_acct_mgmt(pamh, PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS)
|
||
goto auth_pam_fail;
|
||
pam_end(pamh, retval);
|
||
return HANDLER_GO_ON;
|
||
auth_pam_fail:
|
||
log_error_write(srv, __FILE__, __LINE__, "ss", "pam:", pam_strerror(pamh, retval));
|
||
pam_end(pamh, retval);
|
||
return HANDLER_ERROR;
|
||
}
|
||
int mod_authn_pam_plugin_init(plugin *p);
|
||
int mod_authn_pam_plugin_init(plugin *p) {
|
||
p->version = LIGHTTPD_VERSION_ID;
|
||
p->name = buffer_init_string("authn_pam");
|
||
p->init = mod_authn_pam_init;
|
||
p->set_defaults = mod_authn_pam_set_defaults;
|
||
p->cleanup = mod_authn_pam_free;
|
||
p->data = NULL;
|
||
return 0;
|
||
}
|
src/server.c | ||
---|---|---|
#else
|
||
"\t- MySQL support\n"
|
||
#endif
|
||
#ifdef HAVE_LIBPAM
|
||
"\t+ PAM support\n"
|
||
#else
|
||
"\t- PAM support\n"
|
||
#endif
|
||
#ifdef HAVE_KRB5
|
||
"\t+ Kerberos support\n"
|
||
#else
|