File: mod_auth_useragent.c

package info (click to toggle)
libapache-mod-auth-useragent 1.0-9
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 160 kB
  • ctags: 81
  • sloc: sh: 170; makefile: 148; ansic: 135
file content (164 lines) | stat: -rw-r--r-- 5,183 bytes parent folder | download | duplicates (6)
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
};