1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
/*
** mod_auth_useragent.c -- Simple security by User-Agent
*/
#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"
#include "fnmatch.h"
#define AuthUserAgentAllow "Allow a User-Agent that was disallowed"
#define AuthUserAgentDeny "Deny a connection by User-Agent."
/* Copied this out of mod_layout to reuse some code... I am lazy */
#define unless(a) if(!a)
#define WATCHPOINT printf("WATCHPOINT %s %d\n", __FILE__, __LINE__);
module MODULE_VAR_EXPORT auth_useragent_module;
typedef struct {
array_header *allow;
array_header *deny;
} auth_useragent_conf;
int useragent_match(const char *s1, const char *s2) {
if(!s1)
return 1;
if(!s2)
return 1;
return ap_fnmatch(s1, s2, FNM_CASE_BLIND);
}
static void *create_dir_mconfig(pool *p, char *dir) {
auth_useragent_conf *cfg;
cfg = ap_pcalloc(p, sizeof(auth_useragent_conf));
cfg->allow = NULL;
cfg->deny = NULL;
return (void *) cfg;
}
static void *merge_dir_mconfig(pool *p, void *origin, void *new) {
auth_useragent_conf *cfg;
auth_useragent_conf *cfg_new = (auth_useragent_conf *)new;
auth_useragent_conf *cfg_origin = (auth_useragent_conf *)origin;
cfg = ap_pcalloc(p, sizeof(auth_useragent_conf));
cfg->allow = NULL;
cfg->deny = NULL;
if (cfg_new->deny && cfg_origin->deny) {
cfg->deny = ap_append_arrays(p, cfg_origin->deny, cfg_new->deny);
} else if (cfg_new->deny) {
cfg->deny = cfg_new->deny;
} else {
cfg->deny = cfg_origin->deny;
}
if (cfg_new->allow && cfg_origin->allow) {
cfg->allow = ap_append_arrays(p, cfg_origin->allow, cfg_new->allow);
} else if (cfg_new->allow) {
cfg->allow = cfg_new->allow;
} else {
cfg->allow = cfg_origin->allow;
}
return cfg;
}
static int auth_useragent(request_rec *r) {
int true = 0;
int x = 0;
char **items = NULL;
const char *agent = ap_table_get(r->headers_in, "User-Agent");
auth_useragent_conf *cfg = ap_get_module_config (r->per_dir_config, &auth_useragent_module);
/* Yes, you read this right, if there is no agent we say ok
This is not ever ment to be a perfect/reliable form
of security.
*/
#ifdef DEBUG
printf("AUTHUSER: %s\n", agent);
#endif
unless(agent)
return OK;
if (cfg->deny) {
items = (char **) cfg->deny->elts;
for(x = 0; x < cfg->deny->nelts; x++) {
#ifdef DEBUG
printf("AUTHUSER-Deny: %s\n", items[x]);
#endif
if(!useragent_match(items[x], agent)) {
true = 1;
}
}
}
if (cfg->allow) {
items = (char **) cfg->allow->elts;
for(x = 0; x < cfg->allow->nelts; x++) {
#ifdef DEBUG
printf("AUTHUSER-Allow: %s\n", items[x]);
#endif
if(!useragent_match(items[x], agent)) {
true = 0;
}
}
}
return (true ? FORBIDDEN : OK);
}
static const char *user_agent_add(cmd_parms * cmd, void *mconfig, char *param) {
auth_useragent_conf *cfg = (auth_useragent_conf *) mconfig;
struct stat sbuf;
const char *temp;
unless(strcasecmp(cmd->cmd->name, "AuthUserAgentAllow")) {
unless(cfg->allow) {
cfg->allow = ap_make_array (cmd->pool, 1, sizeof (char *));
}
*(char **) ap_push_array (cfg->allow) = (char *) param;
} else unless(strcasecmp(cmd->cmd->name, "AuthUserAgentDeny")) {
unless(cfg->deny) {
cfg->deny = ap_make_array (cmd->pool, 1, sizeof (char *));
}
*(char **) ap_push_array (cfg->deny) = (char *) param;
}
return NULL;
}
static const command_rec auth_useragent_cmds[] = {
{"AuthUserAgentDeny", user_agent_add, NULL, OR_ALL, TAKE1, AuthUserAgentDeny},
{"AuthUserAgentAllow", user_agent_add, NULL, OR_ALL, TAKE1, AuthUserAgentAllow},
{NULL},
};
/* Dispatch list for API hooks */
module MODULE_VAR_EXPORT auth_useragent_module = {
STANDARD_MODULE_STUFF,
NULL, /* module initializer */
create_dir_mconfig, /* create per-dir config structures */
merge_dir_mconfig, /* merge per-dir config structures */
NULL, /* create per-server config structures */
NULL, /* merge per-server config structures */
auth_useragent_cmds, /* table of config file commands */
NULL, /* [#8] MIME-typed-dispatched handlers */
NULL, /* [#1] URI to filename translation */
NULL, /* [#4] validate user id from request */
NULL, /* [#5] check if the user is ok _here_ */
auth_useragent, /* [#3] check access by host address */
NULL, /* [#6] determine MIME type */
NULL, /* [#7] pre-run fixups */
NULL, /* [#9] log a transaction */
NULL, /* [#2] header parser */
NULL, /* child_init */
NULL, /* child_exit */
NULL /* [#0] post read-request */
#ifdef EAPI
,NULL, /* EAPI: add_module */
NULL, /* EAPI: remove_module */
NULL, /* EAPI: rewrite_command */
NULL /* EAPI: new_connection */
#endif
};
|