source: server/common/oursrc/httpdmods/mod_auth_sslcert.c @ 760

Last change on this file since 760 was 436, checked in by andersk, 17 years ago
Fix dir config merging in mod_auth_sslcert.
File size: 5.3 KB
Line 
1/* mod_auth_sslcert
2 * version 1.1.1, released 2007-10-01
3 * Anders Kaseorg <andersk@mit.edu>
4 *
5 * This module does authentication based on SSL client certificates:
6 *   AuthType SSLCert
7 *   AuthSSLCertVar SSL_CLIENT_S_DN_Email
8 *   AuthSSLCertStripSuffix "@MIT.EDU"
9 */
10
11#include "apr_strings.h"
12#define APR_WANT_STRFUNC        /* for strcasecmp */
13#include "apr_want.h"
14
15#include "ap_config.h"
16#include "httpd.h"
17#include "http_config.h"
18#include "http_core.h"
19#include "http_log.h"
20#include "http_request.h"
21
22#include "mod_auth.h"
23#include "mod_ssl.h"
24
25static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *ssl_var_lookup;
26
27typedef struct {
28    int authoritative;
29    char *var;
30    char *strip_suffix;
31    int strip_suffix_required;
32} auth_sslcert_config_rec;
33
34static void *create_auth_sslcert_dir_config(apr_pool_t *p, char *dirspec)
35{
36    auth_sslcert_config_rec *conf = apr_pcalloc(p, sizeof(*conf));
37
38    conf->authoritative = -1;
39    conf->var = NULL;
40    conf->strip_suffix = NULL;
41    conf->strip_suffix_required = -1;
42
43    return conf;
44}
45
46static void *merge_auth_sslcert_dir_config(apr_pool_t *p, void *parent_conf, void *newloc_conf)
47{
48    auth_sslcert_config_rec *pconf = parent_conf, *nconf = newloc_conf,
49        *conf = apr_pcalloc(p, sizeof(*conf));
50
51    conf->authoritative = (nconf->authoritative != -1) ?
52        nconf->authoritative : pconf->authoritative;
53    conf->var = (nconf->var != NULL) ?
54        nconf->var : pconf->var;
55    conf->strip_suffix = (nconf->var != NULL || nconf->strip_suffix != NULL) ?
56        nconf->strip_suffix : pconf->strip_suffix;
57    conf->strip_suffix_required = (nconf->var != NULL || nconf->strip_suffix_required != -1) ?
58        nconf->authoritative : pconf->authoritative;
59
60    return conf;
61}
62
63static const command_rec auth_sslcert_cmds[] =
64{
65    AP_INIT_FLAG("AuthSSLCertAuthoritative", ap_set_flag_slot,
66                 (void *)APR_OFFSETOF(auth_sslcert_config_rec, authoritative),
67                 OR_AUTHCFG,
68                 "Set to 'Off' to allow access control to be passed along to "
69                 "lower modules if the UserID is not known to this module"),
70    AP_INIT_TAKE1("AuthSSLCertVar", ap_set_string_slot,
71                  (void*)APR_OFFSETOF(auth_sslcert_config_rec, var),
72                  OR_AUTHCFG,
73                  "SSL variable to use as the username"),
74    AP_INIT_TAKE1("AuthSSLCertStripSuffix", ap_set_string_slot,
75                  (void*)APR_OFFSETOF(auth_sslcert_config_rec, strip_suffix),
76                  OR_AUTHCFG,
77                  "An optional suffix to strip from the username"),
78    AP_INIT_FLAG("AuthSSLCertStripSuffixRequired", ap_set_flag_slot,
79                 (void *)APR_OFFSETOF(auth_sslcert_config_rec, strip_suffix_required),
80                 OR_AUTHCFG,
81                 "Set to 'Off' to allow certs that don't end with a recognized "
82                 "suffix to still authenticate"),
83    {NULL}
84};
85
86module AP_MODULE_DECLARE_DATA auth_sslcert_module;
87
88static int authenticate_sslcert_user(request_rec *r)
89{
90    auth_sslcert_config_rec *conf = ap_get_module_config(r->per_dir_config,
91                                                         &auth_sslcert_module);
92    const char *current_auth;
93
94    /* Are we configured to be SSLCert auth? */
95    current_auth = ap_auth_type(r);
96    if (!current_auth || strcasecmp(current_auth, "SSLCert") != 0) {
97        return DECLINED;
98    }
99
100    r->ap_auth_type = "SSLCert";
101
102    if (strcasecmp((char *)ssl_var_lookup(r->pool, r->server, r->connection, r,
103                                          "SSL_CLIENT_VERIFY"),
104                   "SUCCESS") == 0) {
105        if (conf->var == NULL) {
106            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
107                          "AuthSSLCertVar is not set: \"%s\"", r->uri);
108            return HTTP_INTERNAL_SERVER_ERROR;
109        }
110        char *user = (char *)ssl_var_lookup(r->pool, r->server, r->connection, r,
111                                            conf->var);
112        if (user != NULL && user[0] != '\0') {
113            if (conf->strip_suffix != NULL) {
114                int i = strlen(user) - strlen(conf->strip_suffix);
115                if (i >= 0 && strcasecmp(user + i, conf->strip_suffix) == 0) {
116                    r->user = apr_pstrmemdup(r->pool, user, i);
117                    return OK;
118                } else if (!conf->strip_suffix_required) {
119                    r->user = user;
120                    return OK;
121                } else {
122                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
123                                  "SSL username for \"%s\" has wrong suffix: \"%s\"",
124                                  r->uri, user);
125                }
126            } else {
127                r->user = user;
128                return OK;
129            }
130        } else {
131            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
132                          "no SSL username for \"%s\"", r->uri);
133        }
134    } else if (conf->authoritative) {
135        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
136                      "SSL client not verified for \"%s\"", r->uri);
137    }
138
139    /* If we're not authoritative, then any error is ignored. */
140    if (!conf->authoritative) {
141        return DECLINED;
142    }
143
144    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
145                  "SSLCert authentication failure for \"%s\"",
146                  r->uri);
147    return HTTP_UNAUTHORIZED;
148}
149
150static void import_ssl_var_lookup()
151{
152    ssl_var_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
153}
154
155static void register_hooks(apr_pool_t *p)
156{
157    ap_hook_check_user_id(authenticate_sslcert_user, NULL, NULL, APR_HOOK_MIDDLE);
158    ap_hook_optional_fn_retrieve(import_ssl_var_lookup, NULL, NULL, APR_HOOK_MIDDLE);
159}
160
161module AP_MODULE_DECLARE_DATA auth_sslcert_module =
162{
163    STANDARD20_MODULE_STUFF,
164    create_auth_sslcert_dir_config,  /* dir config creater */
165    merge_auth_sslcert_dir_config,   /* dir merger */
166    NULL,                            /* server config */
167    NULL,                            /* merge server config */
168    auth_sslcert_cmds,               /* command apr_table_t */
169    register_hooks                   /* register hooks */
170};
Note: See TracBrowser for help on using the repository browser.