Project

General

Profile

Feature #688 » 0002-pam-auth.patch

sravas, 2018-04-10 13:16

View differences:

configure.ac
257 257
fi
258 258
AM_CONDITIONAL(BUILD_WITH_LDAP, test ! $WITH_LDAP = no)
259 259

  
260
dnl Check for PAM
261
AC_MSG_CHECKING(for PAM support)
262
AC_ARG_WITH(pam, AC_HELP_STRING([--with-pam],[enable PAM support]),
263
[WITH_PAM=$withval], [WITH_PAM=no])
264
AC_MSG_RESULT([$withval])
265
if test "$WITH_PAM" != "no"; then
266
 AC_CHECK_LIB(pam, pam_start, [
267
  AC_CHECK_HEADERS([security/pam_appl.h],[
268
    PAM_LIB=-lpam
269
    AC_DEFINE([HAVE_LIBPAM], [1], [libpam])
270
    AC_DEFINE([HAVE_SECURITY_PAM_APPL_H], [1])
271
  ])
272
 ])
273
 AC_SUBST(PAM_LIB)
274
fi
275
AM_CONDITIONAL(BUILD_WITH_PAM, test ! $WITH_PAM = no)
276

  
260 277
dnl Check for xattr
261 278
AC_MSG_CHECKING(for extended attributes support)
262 279
AC_ARG_WITH(attr, AC_HELP_STRING([--with-attr],[enable extended attribute support]),
......
1001 1018
	no_build="$no_build $plugins"
1002 1019
fi
1003 1020

  
1021
plugins="mod_authn_pam"
1022
if test ! "x$PAM_LIB" = x; then
1023
	do_build="$do_build $plugins"
1024
else
1025
	no_build="$no_build $plugins"
1026
fi
1027

  
1004 1028
features="network-openssl"
1005 1029
if test ! "x$SSL_LIB" = x; then
1006 1030
	enable_feature="$enable_feature $features"
src/Makefile.am
292 292
mod_authn_ldap_la_LIBADD = $(LDAP_LIB) $(LBER_LIB) $(common_libadd)
293 293
endif
294 294

  
295
if BUILD_WITH_PAM
296
lib_LTLIBRARIES += mod_authn_pam.la
297
mod_authn_pam_la_SOURCES = mod_authn_pam.c
298
mod_authn_pam_la_LDFLAGS = $(common_module_ldflags)
299
mod_authn_pam_la_LIBADD = $(PAM_LIB) $(common_libadd)
300
endif
301

  
295 302
if BUILD_WITH_MYSQL
296 303
lib_LTLIBRARIES += mod_authn_mysql.la
297 304
mod_authn_mysql_la_SOURCES = mod_authn_mysql.c
src/configfile.c
25 25
#include <glob.h>
26 26

  
27 27

  
28
#if defined(HAVE_MYSQL) || (defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER))
28
#if defined(HAVE_LIBPAM) || defined(HAVE_MYSQL) || (defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER))
29 29
static void config_warn_authn_module (server *srv, const char *module) {
30 30
	size_t len = strlen(module);
31 31
	for (size_t i = 0; i < srv->config_context->used; ++i) {
......
372 372
		int append_mod_authn_file = 1;
373 373
		int append_mod_authn_ldap = 1;
374 374
		int append_mod_authn_mysql = 1;
375
		int append_mod_authn_pam = 1;
375 376
		int contains_mod_auth = 0;
376 377

  
377 378
		/* prepend default modules */
......
402 403
				append_mod_authn_mysql = 0;
403 404
			}
404 405

  
406
			if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_authn_pam"))) {
407
				append_mod_authn_pam = 0;
408
			}
409

  
405 410
			if (buffer_is_equal_string(ds->value, CONST_STR_LEN("mod_auth"))) {
406 411
				contains_mod_auth = 1;
407 412
			}
......
412 417
			    0 == append_mod_authn_file &&
413 418
			    0 == append_mod_authn_ldap &&
414 419
			    0 == append_mod_authn_mysql &&
420
			    0 == append_mod_authn_pam &&
415 421
			    1 == contains_mod_auth) {
416 422
				break;
417 423
			}
src/mod_authn_pam.c
1
#include "first.h"
2

  
3
#define USE_PAM
4
#include <security/pam_appl.h>
5

  
6
#include "server.h"
7
#include "http_auth.h"
8
#include "log.h"
9
#include "plugin.h"
10

  
11
#include <errno.h>
12
#include <string.h>
13

  
14
typedef struct {
15
	buffer *auth_pam_servicename;
16
} plugin_config;
17

  
18
typedef struct {
19
    PLUGIN_DATA;
20
    plugin_config **config_storage;
21
    plugin_config conf, *anon_conf; /* this is only used as long as no handler_ctx is setup */
22
} plugin_data;
23

  
24
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);
25

  
26
INIT_FUNC(mod_authn_pam_init) {
27
    static http_auth_backend_t http_auth_backend_pam =
28
      { "pam", mod_authn_pam_basic, NULL, NULL };
29
    plugin_data *p = calloc(1, sizeof(*p));
30

  
31
    /* register http_auth_backend_pam */
32
    http_auth_backend_pam.p_d = p;
33
    http_auth_backend_set(&http_auth_backend_pam);
34

  
35
    return p;
36
}
37

  
38
FREE_FUNC(mod_authn_pam_free) {
39
    plugin_data *p = p_d;
40

  
41
    UNUSED(srv);
42

  
43
    if (!p) return HANDLER_GO_ON;
44

  
45
    if (p->config_storage) {
46
        size_t i;
47
        for (i = 0; i < srv->config_context->used; i++) {
48
            plugin_config *s = p->config_storage[i];
49

  
50
            if (NULL == s) continue;
51

  
52
            buffer_free(s->auth_pam_servicename);
53
            free(s);
54
        }
55
        free(p->config_storage);
56
    }
57

  
58
    free(p);
59

  
60
    return HANDLER_GO_ON;
61
}
62

  
63
SETDEFAULTS_FUNC(mod_authn_pam_set_defaults) {
64
    plugin_data *p = p_d;
65
    size_t i;
66
config_values_t cv[] = {
67
		{ "auth.backend.pam.service-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
68
        { NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
69
    };
70

  
71
    p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
72

  
73
    for (i = 0; i < srv->config_context->used; i++) {
74
        data_config const* config = (data_config const*)srv->config_context->data[i];
75
        plugin_config *s;
76

  
77
        s = calloc(1, sizeof(plugin_config));
78

  
79
        s->auth_pam_servicename = buffer_init();
80

  
81
        cv[0].destination = s->auth_pam_servicename;
82

  
83
        p->config_storage[i] = s;
84

  
85
        if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
86
            return HANDLER_ERROR;
87
        }
88
    }
89

  
90
    return HANDLER_GO_ON;
91
}
92

  
93
#define PATCH(x) \
94
    p->conf.x = s->x;
95
static int mod_authn_pam_patch_connection(server *srv, connection *con, plugin_data *p) {
96
    size_t i, j;
97
    plugin_config *s = p->config_storage[0];
98

  
99
    PATCH(auth_pam_servicename);
100

  
101
    /* skip the first, the global context */
102
    for (i = 1; i < srv->config_context->used; i++) {
103
        data_config *dc = (data_config *)srv->config_context->data[i];
104
        s = p->config_storage[i];
105

  
106
        /* condition didn't match */
107
        if (!config_check_cond(srv, con, dc)) continue;
108

  
109
        /* merge config */
110
        for (j = 0; j < dc->value->used; j++) {
111
            data_unset *du = dc->value->data[j];
112

  
113
            if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.pam.service-name"))) {
114
                PATCH(auth_pam_servicename);
115
            }
116
        }
117
    }
118

  
119
    return 0;
120
}
121
#undef PATCH
122

  
123
typedef struct {
124
    plugin_config *conf;
125
    const char *username;
126
    const char *realm;
127
    const char *password;
128
} mod_auth_pam_data;
129

  
130
static int mod_authn_pam_fn_conv(int num_msg, const struct pam_message **msg, struct pam_response **p_resp, void *appdata_ptr)  {
131
    mod_auth_pam_data *p_pam = (mod_auth_pam_data *)appdata_ptr;
132
    struct pam_response *resp = (struct pam_response *)malloc(num_msg * sizeof(struct pam_response));
133

  
134
    for(int i = 0; i < num_msg; ++i) {
135
        switch(msg[i]->msg_style) {
136
            case PAM_PROMPT_ECHO_OFF:
137
            case PAM_PROMPT_ECHO_ON:
138
                resp[i].resp = strdup(p_pam->password);
139
                resp[i].resp_retcode = 0;
140
                break;
141
            case PAM_ERROR_MSG:
142
            case PAM_TEXT_INFO:
143
            default:
144
                // ignore
145
                resp[i].resp_retcode = 0;
146
                resp[i].resp = NULL;
147
                continue;
148
        }
149
    }
150

  
151
    *p_resp = resp;
152

  
153
    return PAM_SUCCESS;
154
}
155

  
156
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) {
157
    plugin_data *p = (plugin_data *)p_d;
158
    pam_handle_t *pamh = NULL;
159
    mod_auth_pam_data pam_data = {
160
        &p->conf,
161
        username->ptr,
162
        require->realm->ptr,
163
        pw
164
    };
165
    struct pam_conv conv = { mod_authn_pam_fn_conv, &pam_data };
166
    
167
	mod_authn_pam_patch_connection(srv, con, p);
168

  
169
    int retval = pam_start(
170
            !buffer_is_empty(p->conf.auth_pam_servicename) ? p->conf.auth_pam_servicename->ptr : "lighttpd",
171
            username->ptr,
172
            &conv,
173
            &pamh);
174

  
175
    if(retval != PAM_SUCCESS)
176
        goto auth_pam_fail;
177

  
178
    if((retval = pam_authenticate(pamh, PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS)
179
        goto auth_pam_fail;
180

  
181
    if((retval = pam_acct_mgmt(pamh, PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS)
182
        goto auth_pam_fail;
183

  
184
    pam_end(pamh, retval);
185
    return HANDLER_GO_ON;
186

  
187
auth_pam_fail:
188
    log_error_write(srv, __FILE__, __LINE__, "ss", "pam:", pam_strerror(pamh, retval));
189
    pam_end(pamh, retval);
190
    return HANDLER_ERROR;
191
}
192

  
193
int mod_authn_pam_plugin_init(plugin *p);
194
int mod_authn_pam_plugin_init(plugin *p) {
195
    p->version     = LIGHTTPD_VERSION_ID;
196
    p->name        = buffer_init_string("authn_pam");
197
    p->init        = mod_authn_pam_init;
198
    p->set_defaults = mod_authn_pam_set_defaults;
199
    p->cleanup     = mod_authn_pam_free;
200

  
201
    p->data        = NULL;
202

  
203
    return 0;
204
}
src/server.c
655 655
#else
656 656
      "\t- MySQL support\n"
657 657
#endif
658
#ifdef HAVE_LIBPAM
659
	  "\t+ PAM support\n"
660
#else
661
	  "\t- PAM support\n"
662
#endif
658 663
#ifdef HAVE_KRB5
659 664
      "\t+ Kerberos support\n"
660 665
#else
(2-2/3)