Bizanga.pm 8.04 KB
Newer Older
Nigel Kukard's avatar
Nigel Kukard committed
1
# Bizanga protocol support module
Wepongo's avatar
Wepongo committed
2
# Copyright (C) 2009-2015, AllWorldIT
Nigel Kukard's avatar
Nigel Kukard committed
3
# Copyright (C) 2008, LinuxRulz
Nigel Kukard's avatar
Nigel Kukard committed
4
#
Nigel Kukard's avatar
Nigel Kukard committed
5
6
7
8
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
Nigel Kukard's avatar
Nigel Kukard committed
9
#
Nigel Kukard's avatar
Nigel Kukard committed
10
11
12
13
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
Nigel Kukard's avatar
Nigel Kukard committed
14
#
Nigel Kukard's avatar
Nigel Kukard committed
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.


package cbp::protocols::Bizanga;


use strict;
use warnings;


use POSIX;
use URI::Escape;

use cbp::version;
use cbp::logging;
Nigel Kukard's avatar
Nigel Kukard committed
32
use awitpt::db::dblayer;
Nigel Kukard's avatar
Nigel Kukard committed
33
use awitpt::netip;
Nigel Kukard's avatar
Nigel Kukard committed
34
35
36
37
38
use cbp::protocols;


# User plugin info
our $pluginInfo = {
Nigel Kukard's avatar
Nigel Kukard committed
39
40
41
42
43
44
45
46
47
	name => "Bizanga Protocol Support Module",
	ini => \&init,
	priority => 50,
	protocol_init => \&protocol_init,
	protocol_check => \&protocol_check,
	protocol_parse => \&protocol_parse,
	protocol_response => \&protocol_response,
	protocol_getresponse => \&protocol_getresponse,
	protocol_validate => \&protocol_validate,
Nigel Kukard's avatar
Nigel Kukard committed
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
};

# Module configuration
my %config;


# Response data
my ($response,$response_data);


# Create a child specific context
sub init {
	my $server = shift;
	my $inifile = $server->{'inifile'};

	# Defaults
	$config{'enable'} = 1;

	# Check if enabled
	if ($config{'enable'} =~ /^\s*(y|yes|1|on)\s*$/i) {
		$server->log(LOG_NOTICE,"  => Protocol(Bizanga): enabled");
		$config{'enable'} = 1;
	}
}


74
75
76
77
78
79
80
# Initialize per request data...
sub protocol_init {
	$response = undef;
	$response_data = undef;
}


Nigel Kukard's avatar
Nigel Kukard committed
81
82
83
# Check the buffer to see if this protocol is what we want
sub protocol_check {
	my ($server,$buffer) = @_;
84
	my $log = defined($server->{'config'}{'logging'}{'protocols'});
Nigel Kukard's avatar
Nigel Kukard committed
85

Nigel Kukard's avatar
Nigel Kukard committed
86
87
88
89

	# If we not enabled, don't do anything
	return undef if (!$config{'enable'});

90
91
92
93
	# Ignore leading blank lines
	$buffer =~ s/^(?:\015?\012)+//;

	# Check we have at least one line
94
	return 0 if (!($buffer =~ /\012/));
95

Nigel Kukard's avatar
Nigel Kukard committed
96
	# Check for HTTP header
97
	if ($buffer =~ /^GET [^\s]+ HTTP\/(\d+)\.(\d+)\015?\012/) {
Nigel Kukard's avatar
Nigel Kukard committed
98
99
		my ($a,$b) = ($1,$2);

100
		$server->log(LOG_DEBUG,"[PROTOCOLS/Bizanga] Possible Bizanga (HTTP/$a.$b) protocol") if ($log);
101

Nigel Kukard's avatar
Nigel Kukard committed
102
		if ($buffer =~ /\015?\012\015?\012/) {
103
			$server->log(LOG_INFO,"[Protocols/Bizanga] Identified Bizanga (HTTP/$a.$b) protocol") if ($log);
Nigel Kukard's avatar
Nigel Kukard committed
104
105
106
107
108
109
110
111
112
113
114
			return 1;
		}
	}

	return 0;
}


# Process buffer into sessionData
sub protocol_parse {
	my ($server,$buffer) = @_;
115
116
117
	# Get this instance we're working with
	my $serverInstance = $server->{'server'};
	# Are we going to log?
118
	my $log = defined($server->{'config'}{'logging'}{'bizanga'});
Nigel Kukard's avatar
Nigel Kukard committed
119
120
121
122
123
124
125
126
127
128
129
130
131
132

	my %res;

	# remove /?
	$buffer =~ s/^\w+ \/\?//;

	# Loop with each line
	foreach my $item (split /[& ]/, $buffer) {
		# If we don't get a pair, b0rk
		last unless $item =~ s/^([^=]+)=(.*)$//;

		# Clean up strings, and shove into hash
		my ($param,$value) = (uri_unescape($1),uri_unescape($2));
		$res{$param} = $value;
133
		$server->log(LOG_DEBUG,"[BIZANGA] Request parameter '$param' with value '$value'") if ($log);
Nigel Kukard's avatar
Nigel Kukard committed
134
135
136
137
138
139
140
141
142
143
144
145
	}

	# We need some extra info to make everything else happy...
	$res{'protocol_state'} = "RCPT" if (!defined($res{'protocol_state'}));

	$res{'_protocol_transport'} = "HTTP";

	return \%res;
}


# Process response
Nigel Kukard's avatar
Nigel Kukard committed
146
sub protocol_response
Nigel Kukard's avatar
Nigel Kukard committed
147
148
{
	my ($server,$resp,$data) = @_;
Nigel Kukard's avatar
Nigel Kukard committed
149
	my $log = defined($server->{'config'}{'logging'}{'protocols'});
Nigel Kukard's avatar
Nigel Kukard committed
150
151
152
153


	# Check protocol responses...
	if ($resp == PROTO_PASS) {
154
		$response = "200";
Nigel Kukard's avatar
Nigel Kukard committed
155
		$response_data = $data;
Nigel Kukard's avatar
Nigel Kukard committed
156
		$server->log(LOG_DEBUG,"[PROTOCOL/Bizanga] Received PROTO_PASS with response '$response':'$response_data'") if ($log);
Nigel Kukard's avatar
Nigel Kukard committed
157
158
		return CBP_CONTINUE;

159
160
161
	} elsif ($resp == PROTO_OK) {
		$response = "200";
		$response_data = $data;
Nigel Kukard's avatar
Nigel Kukard committed
162
		$server->log(LOG_DEBUG,"[PROTOCOL/Bizanga] Received PROTO_OK with response '$response':'$response_data'") if ($log);
163
164
		return CBP_STOP;

Nigel Kukard's avatar
Nigel Kukard committed
165
166
167
168
169
170
171
172
	} elsif ($resp == PROTO_REJECT) {
		if ($data =~ /^(5[0-9]{2}) (.*)/) {
			$response = "403";
			$response_data = $2;
		} else {
			$response = "403";
			$response_data = $data;
		}
Nigel Kukard's avatar
Nigel Kukard committed
173
		$server->log(LOG_DEBUG,"[PROTOCOL/Bizanga] Received PROTO_REJECT with response '$response':'$response_data'") if ($log);
Nigel Kukard's avatar
Nigel Kukard committed
174
175
176
177
178
179
180
181
182
183
		return CBP_STOP;

	} elsif ($resp == PROTO_DEFER) {
		if ($data =~ /^(4[0-9]{2}) (.*)/) {
			$response = "401";
			$response_data = $2;
		} else {
			$response = "401";
			$response_data = $data;
		}
Nigel Kukard's avatar
Nigel Kukard committed
184
		$server->log(LOG_DEBUG,"[PROTOCOL/Bizanga] Received PROTO_DEFER with response '$response':'$response_data'") if ($log);
Nigel Kukard's avatar
Nigel Kukard committed
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
		return CBP_STOP;

	} elsif ($resp == PROTO_HOLD) {
		$server->log(LOG_ERR,"[PROTOCOL/Bizanga] Unsupported return PROTO_HOLD");
		return CBP_STOP;

	} elsif ($resp == PROTO_REDIRECT) {
		$server->log(LOG_ERR,"[PROTOCOL/Bizanga] Unsupported return PROTO_REDIRECT");
		return CBP_STOP;

	} elsif ($resp == PROTO_DISCARD) {
		$server->log(LOG_ERR,"[PROTOCOL/Bizanga] Unsupported return PROTO_DISCARD");
		return CBP_STOP;

	} elsif ($resp == PROTO_FILTER) {
		$server->log(LOG_ERR,"[PROTOCOL/Bizanga] Unsupported return PROTO_FILTER");
		return CBP_STOP;

	} elsif ($resp == PROTO_PREPEND) {
		$server->log(LOG_ERR,"[PROTOCOL/Bizanga] Unsupported return PROTO_PREPEND");
		return CBP_CONTINUE;

	} elsif ($resp == PROTO_ERROR) {
208
209
		$response = "503";
		$response_data = defined($data) ? $data : "Unknown error";
Nigel Kukard's avatar
Nigel Kukard committed
210
		$server->log(LOG_DEBUG,"[PROTOCOL/Bizanga] Received PROTO_ERROR with response '$response':'$response_data'") if ($log);
Nigel Kukard's avatar
Nigel Kukard committed
211
212
213
		return CBP_STOP;

	} elsif ($resp == PROTO_DB_ERROR) {
214
215
		$response = "504";
		$response_data = defined($data) ? $data : "Database error";
Nigel Kukard's avatar
Nigel Kukard committed
216
		$server->log(LOG_DEBUG,"[PROTOCOL/Bizanga] Received PROTO_DB_ERROR with response '$response':'$response_data'") if ($log);
Nigel Kukard's avatar
Nigel Kukard committed
217
		return CBP_STOP;
Nigel Kukard's avatar
Nigel Kukard committed
218

Nigel Kukard's avatar
Nigel Kukard committed
219
	} elsif ($resp == PROTO_DATA_ERROR) {
220
221
		$response = "502";
		$response_data = defined($data) ? $data : "Database record error";
Nigel Kukard's avatar
Nigel Kukard committed
222
		$server->log(LOG_DEBUG,"[PROTOCOL/Bizanga] Received PROTO_DATA_ERROR with response '$response':'$response_data'") if ($log);
Nigel Kukard's avatar
Nigel Kukard committed
223
		return CBP_STOP;
Nigel Kukard's avatar
Nigel Kukard committed
224

Nigel Kukard's avatar
Nigel Kukard committed
225
226
	# Fallthrough
	} else {
Nigel Kukard's avatar
Nigel Kukard committed
227
		$server->log(LOG_ERR,"[PROTOCOL/Bizanga] Cannot understand response code '$resp'");
Nigel Kukard's avatar
Nigel Kukard committed
228
229
230
231
232
233
		return CBP_ERROR;
	}
}


# Get protocol response
Nigel Kukard's avatar
Nigel Kukard committed
234
sub protocol_getresponse
Nigel Kukard's avatar
Nigel Kukard committed
235
236
237
238
239
240
{
	my $resp;


	# If its undefined, set to DUNNO
	if (!defined($response)) {
241
		$response = "200";
Nigel Kukard's avatar
Nigel Kukard committed
242
243
244
		$response_data = "Pass";
	}

Nigel Kukard's avatar
Nigel Kukard committed
245
	# Check if we have any additional data
Nigel Kukard's avatar
Nigel Kukard committed
246
	$response_data = "" if (!defined($response_data));
Nigel Kukard's avatar
Nigel Kukard committed
247

Nigel Kukard's avatar
Nigel Kukard committed
248
249
250
251
	# Get timestamp
	my $timestamp = strftime("%a, %d %b %Y %H:%M:%S %Z",localtime());

	# Construct response
252
	$resp = "HTTP/1.0 $response $response_data
Nigel Kukard's avatar
Nigel Kukard committed
253
254
255
Date: $timestamp
Content-Length: 0
Content-Type: text/plain
Nigel Kukard's avatar
Nigel Kukard committed
256
Server: PolicyD/".VERSION." (Cluebringer)
Nigel Kukard's avatar
Nigel Kukard committed
257
Connection: close
258
";
Nigel Kukard's avatar
Nigel Kukard committed
259

260
	return "$resp\n"
Nigel Kukard's avatar
Nigel Kukard committed
261
262
263
}


264
265
266
# Validate protocol data
sub protocol_validate {
	my ($server,$request) = @_;
267
	my $log = defined($server->{'config'}{'logging'}{'protocols'});
Nigel Kukard's avatar
Nigel Kukard committed
268

269
270

	# Check params
Nigel Kukard's avatar
Nigel Kukard committed
271
	if (!awitpt::netip::is_valid($request->{'client_address'})) {
272
273
		my $client_address = defined($request->{'client_address'}) ? "'".$request->{'client_address'}."'" : "undef";
		$server->log(LOG_DEBUG,"[PROTOCOLS/Bizanga] Error, parameter 'client_address' cannot be $client_address") if ($log);
274
275
276
		return "Required parameter 'client_address' was not found or invalid format";
	}

277
	if (!defined($request->{'sender'}) || !($request->{'sender'} =~ /^(?:\S+@\S+|)$/) ) {
278
279
		my $sender = defined($request->{'sender'}) ? "'".$request->{'sender'}."'" : "undef";
		$server->log(LOG_DEBUG,"[PROTOCOLS/Bizanga] Error, parameter 'sender' cannot be $sender") if ($log);
280
281
282
283
		return "Required parameter 'sender' was not found or invalid format";
	}

	if (!defined($request->{'recipient'}) || !($request->{'recipient'} =~ /^\S+@\S+$/) ) {
284
285
		my $recipient = defined($request->{'recipient'}) ? "'".$request->{'recipient'}."'" : "undef";
		$server->log(LOG_DEBUG,"[PROTOCOLS/Bizanga] Error, parameter 'recipient' cannot be $recipient") if ($log);
286
287
288
289
290
		return "Required parameter 'recipient' was not found or invalid format";
	}
}


Nigel Kukard's avatar
Nigel Kukard committed
291
292
293

1;
# vim: ts=4