SPECIAL_REQUEST_URI,
SPECIAL_REQUEST_METHOD,
SPECIAL_REQUEST_PROTOCOL,
- SPECIAL_SERVER_ADDR
+ SPECIAL_SERVER_ADDR,
+ SPECIAL_OID_VALUE
};
typedef struct {
char *name; /* header name */
} sei_cfg_rec;
module AP_MODULE_DECLARE_DATA setenvif_module;
+#if (MODULE_MAGIC_NUMBER_MAJOR > 20020903)
+#include "mod_ssl.h"
+#else
+APR_DECLARE_OPTIONAL_FN(apr_array_header_t *, ssl_extlist_by_oid, (request_rec *r, const char *oidstr));
+#endif
+static APR_OPTIONAL_FN_TYPE(ssl_extlist_by_oid) *ssl_extlist_by_oid_func = NULL;
/*
* These routines, the create- and merge-config functions, are called
else if (!strcasecmp(fname, "server_addr")) {
new->special_type = SPECIAL_SERVER_ADDR;
}
+ else if (!strncasecmp(fname, "oid(",4)) {
+ ap_regmatch_t match[AP_MAX_REG_MATCH];
+
+ new->special_type = SPECIAL_OID_VALUE;
+
+ /* Syntax check and extraction of the OID as a regex: */
+ new->pnamereg = ap_pregcomp(cmd->pool,
+ "^oid\\(\"?([0-9.]+)\"?\\)$",
+ (AP_REG_EXTENDED // | AP_REG_NOSUB
+ | AP_REG_ICASE));
+ /* this can never happen, as long as pcre works:
+ if (new->pnamereg == NULL)
+ return apr_pstrcat(cmd->pool, cmd->cmd->name,
+ "OID regex could not be compiled.", NULL);
+ */
+ if (ap_regexec(new->pnamereg, fname, AP_MAX_REG_MATCH, match, 0) == AP_REG_NOMATCH) {
+ return apr_pstrcat(cmd->pool, cmd->cmd->name,
+ "OID syntax is: oid(\"1.2.3.4.5\"); error in: ",
+ fname, NULL);
+ }
+ new->pnamereg = NULL;
+ /* The name field is used for the stripped oid string */
+ new->name = fname = apr_pstrdup(cmd->pool, fname+match[1].rm_so);
+ fname[match[1].rm_eo - match[1].rm_so] = '\0';
+ }
else {
new->special_type = SPECIAL_NOT;
/* Handle fname as a regular expression.
* same header. Remember we don't need to strcmp the two header
* names because we made sure the pointers were equal during
* configuration.
+ * In the case of SPECIAL_OID_VALUE values, each oid string is
+ * dynamically allocated, thus there are no duplicates.
*/
if (b->name != last_name) {
last_name = b->name;
case SPECIAL_REQUEST_PROTOCOL:
val = r->protocol;
break;
+ case SPECIAL_OID_VALUE:
+ /* If mod_ssl is not loaded, the accessor function is NULL */
+ if (ssl_extlist_by_oid_func != NULL)
+ {
+ apr_array_header_t *oid_array;
+ char **oid_value;
+ int j, len = 0;
+ char *retval = NULL;
+
+ /* The given oid can occur multiple times. Concatenate the values */
+ if ((oid_array = ssl_extlist_by_oid_func(r, b->name)) != NULL) {
+ oid_value = (char **) oid_array->elts;
+ /* pass 1: determine the size of the string */
+ for (len=j=0; j < oid_array->nelts; j++) {
+ len += strlen(oid_value[j]) + 1; /* +1 for ',' or terminating NIL */
+ }
+ retval = apr_palloc(r->pool, len);
+ /* pass 2: fill the string */
+ for (j=0; j < oid_array->nelts; j++) {
+ if (j > 0) {
+ strcat(retval, ",");
+ }
+ strcat(retval, oid_value[j]);
+ }
+ }
+ val = retval;
+ }
+ break;
case SPECIAL_NOT:
if (b->pnamereg) {
/* Matching headers_in against a regex. Iterate through
return DECLINED;
}
+static int
+setenvif_post_config()
+{
+ ssl_extlist_by_oid_func = APR_RETRIEVE_OPTIONAL_FN(ssl_extlist_by_oid);
+ return OK;
+}
+
static void register_hooks(apr_pool_t *p)
{
ap_hook_header_parser(match_headers, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_post_read_request(match_headers, NULL, NULL, APR_HOOK_MIDDLE);
+ /* post config handling */
+ ap_hook_post_config(setenvif_post_config, NULL, NULL, APR_HOOK_MIDDLE);
}
module AP_MODULE_DECLARE_DATA setenvif_module =
static BOOL ssl_expr_eval_comp(request_rec *, ssl_expr *);
static char *ssl_expr_eval_word(request_rec *, ssl_expr *);
-static BOOL ssl_expr_eval_oid(const char *w, request_rec *r, const char *oidstr);
+static BOOL ssl_expr_eval_oid(request_rec *r, const char *word, const char *oidstr);
static char *ssl_expr_eval_func_file(request_rec *, char *);
static int ssl_expr_eval_strcmplex(char *, char *);
if (op == op_OidListElement) {
char *w3 = ssl_expr_eval_word(r, e3);
- found = ssl_expr_eval_oid(w1, r, w3);
+ found = ssl_expr_eval_oid(r, w1, w3);
/* There will be no more nodes on the list, so the result is authoritative */
break;
}
}
-static BOOL ssl_expr_eval_oid(const char *word, request_rec *r, const char *oidstr)
+#define NUM_OID_ELTS 8 /* start with 8 oid slots, resize when needed */
+
+apr_array_header_t *ssl_extlist_by_oid(request_rec *r, const char *oidstr)
{
- SSLConnRec *sslconn = myConnConfig(r->connection);
- SSL *ssl;
+ int count = 0, j;
X509 *xs = NULL;
ASN1_OBJECT *oid;
- int count = 0, j;
- BOOL result = FALSE;
-
- if (!oidstr || !sslconn || !sslconn->ssl)
- return FALSE;
+ apr_array_header_t *val_array;
+ SSLConnRec *sslconn = myConnConfig(r->connection);
- ssl = sslconn->ssl;
+ /* trivia */
+ if (oidstr == NULL || sslconn == NULL || sslconn->ssl == NULL)
+ return NULL;
- oid = OBJ_txt2obj(oidstr, 1);
- if (!oid) {
+ /* Determine the oid we are looking for */
+ if ((oid = OBJ_txt2obj(oidstr, 1)) == NULL) {
ERR_clear_error();
- return FALSE;
+ return NULL;
}
- xs = SSL_get_peer_certificate(ssl);
- if (xs == NULL) {
- return FALSE;
+ /* are there any extensions in the cert? */
+ if ((xs = SSL_get_peer_certificate(sslconn->ssl)) == NULL ||
+ (count = X509_get_ext_count(xs)) == 0) {
+ return NULL;
}
- count = X509_get_ext_count(xs);
+ val_array = apr_array_make(r->pool, NUM_OID_ELTS, sizeof(char *));
+ /* Loop over all extensions, extract the desired oids */
for (j = 0; j < count; j++) {
X509_EXTENSION *ext = X509_get_ext(xs, j);
if (X509V3_EXT_print(bio, ext, 0, 0) == 1) {
BUF_MEM *buf;
+ char **new = apr_array_push(val_array);
BIO_get_mem_ptr(bio, &buf);
- if (strcmp(word, buf->data) == 0)
- result = TRUE;
+ *new = apr_pstrdup(r->pool, buf->data);
}
BIO_vfree(bio);
- if (result != FALSE)
- break;
}
}
X509_free(xs);
ERR_clear_error();
+
+ if (val_array->nelts == 0)
+ return NULL;
+ else
+ return val_array;
+}
+
+static BOOL ssl_expr_eval_oid(request_rec *r, const char *word, const char *oidstr)
+{
+ SSLConnRec *sslconn = myConnConfig(r->connection);
+ int j;
+ BOOL result = FALSE;
+ apr_array_header_t *oid_array;
+ char **oid_value;
+
+ if (NULL == (oid_array = ssl_extlist_by_oid(r, oidstr))) {
+ return FALSE;
+ }
+
+ oid_value = (char **) oid_array->elts;
+ for (j = 0; j < oid_array->nelts; j++) {
+ if (strcmp(word, oid_value[j]) == 0) {
+ result = TRUE;
+ break;
+ }
+ }
return result;
}