Project

General

Profile

Download (22.5 KB) Statistics
| Branch: | Tag: | Revision:
1 336e3c1c Charlie
<?php
2
/*
3 ac24dc24 Renato Botelho
 * voucher.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6 b8f91b7c Luiz Souza
 * Copyright (c) 2007-2018 Rubicon Communications, LLC (Netgate)
7 c5d81585 Renato Botelho
 * Copyright (c) 2007 Marcel Wiget <mwiget@mac.com>
8 ac24dc24 Renato Botelho
 * All rights reserved.
9
 *
10
 * originally part of m0n0wall (http://m0n0.ch/wall)
11 c5d81585 Renato Botelho
 * Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>.
12 ac24dc24 Renato Botelho
 * All rights reserved.
13
 *
14 b12ea3fb Renato Botelho
 * Licensed under the Apache License, Version 2.0 (the "License");
15
 * you may not use this file except in compliance with the License.
16
 * You may obtain a copy of the License at
17 ac24dc24 Renato Botelho
 *
18 b12ea3fb Renato Botelho
 * http://www.apache.org/licenses/LICENSE-2.0
19 ac24dc24 Renato Botelho
 *
20 b12ea3fb Renato Botelho
 * Unless required by applicable law or agreed to in writing, software
21
 * distributed under the License is distributed on an "AS IS" BASIS,
22
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23
 * See the License for the specific language governing permissions and
24
 * limitations under the License.
25 ac24dc24 Renato Botelho
 */
26 523855b0 Scott Ullrich
27 336e3c1c Charlie
/* include all configuration functions */
28 79262830 Phil Davis
if (!function_exists('captiveportal_syslog')) {
29 4e8d55dd Scott Ullrich
	require_once("captiveportal.inc");
30 79262830 Phil Davis
}
31 336e3c1c Charlie
32 b8963db6 Renato Botelho
function xmlrpc_sync_voucher_details(&$syncip, &$port, &$username, &$password) {
33
	global $config;
34
35
	if (!empty($config['voucher'][$cpzone]['vouchersyncdbip'])) {
36
		$syncip = $config['voucher'][$cpzone]['vouchersyncdbip'];
37
		$port = $config['voucher'][$cpzone]['vouchersyncport'];
38
		$username = $config['voucher'][$cpzone]['vouchersyncusername'];
39
		$password = $config['voucher'][$cpzone]['vouchersyncpass'];
40
		return true;
41
	}
42
43
	if (!is_array($config['hasync']) ||
44
	    empty($config['hasync']['synchronizetoip']) ||
45
	    $config['hasync']['synchronizecaptiveportal'] == "") {
46
		return false;
47
	}
48
49
	$syncip = $config['hasync']['synchronizetoip'];
50
	$password = $config['hasync']['password'];
51
	if (empty($config['hasync']['username'])) {
52
		$username = "admin";
53
	} else {
54
		$username = $config['hasync']['username'];
55
	}
56
57
	/* if port is empty lets rely on the protocol selection */
58
	$port = $config['system']['webgui']['port'];
59
	if (empty($port)) {
60
		if ($config['system']['webgui']['protocol'] == "http") {
61
			$port = "80";
62
		} else {
63
			$port = "443";
64
		}
65
	}
66
67
	return true;
68
}
69
70 05771a24 Ermal
function xmlrpc_sync_voucher_expire($vouchers, $syncip, $port, $password, $username) {
71 a8620841 PiBa-NL
	global $cpzone;
72
	require_once("xmlrpc_client.inc");
73 179377b0 robjarsen
74 05771a24 Ermal
	/* Construct code that is run on remote machine */
75 6c07db48 Phil Davis
	$execcmd = <<<EOF
76 fac36dfd Ermal
	global \$cpzone;
77 05771a24 Ermal
	require_once('/etc/inc/captiveportal.inc');
78
	require_once('/etc/inc/voucher.inc');
79 a18eeb51 bcyrill
	\$cpzone = "$cpzone";
80 927a988e jim-p
	return voucher_expire("$vouchers");
81 05771a24 Ermal
82
EOF;
83 e3b0eeb2 PiBa-NL
	$rpc_client = new pfsense_xmlrpc_client();
84
	$rpc_client->setConnectionData($syncip, $port, $username, $password);
85 a8620841 PiBa-NL
	$resp = $rpc_client->xmlrpc_exec_php($execcmd);
86
	if (empty($resp)) {
87 200728c9 Renato Botelho
		return false;
88
	}
89
	return $resp;
90 05771a24 Ermal
}
91
92 a18eeb51 bcyrill
function xmlrpc_sync_voucher_disconnect($dbent, $syncip, $port, $password, $username, $term_cause = 1, $stop_time = null) {
93 a8620841 PiBa-NL
	global $cpzone;
94
	require_once("xmlrpc_client.inc");
95 d322e3b3 Scott Ullrich
	/* Construct code that is run on remote machine */
96 a8620841 PiBa-NL
	$dbent_str = addslashes(serialize($dbent));
97 bbe29bb1 bcyrill
	$tmp_stop_time = (isset($stop_time)) ? $stop_time : "null";
98 6c07db48 Phil Davis
	$execcmd = <<<EOF
99 fac36dfd Ermal
	global \$cpzone;
100 d322e3b3 Scott Ullrich
	require_once('/etc/inc/captiveportal.inc');
101
	require_once('/etc/inc/voucher.inc');
102 a18eeb51 bcyrill
	\$cpzone = "$cpzone";
103 d322e3b3 Scott Ullrich
	\$radiusservers = captiveportal_get_radius_servers();
104 a18eeb51 bcyrill
	\$dbent = unserialize("$dbent_str");
105 927a988e jim-p
	return captiveportal_disconnect(\$dbent, \$radiusservers, $term_cause, $tmp_stop_time);
106 d322e3b3 Scott Ullrich
107
EOF;
108 e3b0eeb2 PiBa-NL
	$rpc_client = new pfsense_xmlrpc_client();
109
	$rpc_client->setConnectionData($syncip, $port, $username, $password);
110 a8620841 PiBa-NL
	$resp = $rpc_client->xmlrpc_exec_php($execcmd);
111
	if (empty($resp)) {
112 200728c9 Renato Botelho
		return false;
113
	}
114
	return $resp;
115 d322e3b3 Scott Ullrich
}
116
117 6c9ca678 Scott Ullrich
function xmlrpc_sync_used_voucher($voucher_received, $syncip, $port, $password, $username) {
118 a8620841 PiBa-NL
	global $config, $cpzone;
119
	require_once("xmlrpc_client.inc");
120 6c9ca678 Scott Ullrich
121
	/* Construct code that is run on remote machine */
122 6c07db48 Phil Davis
	$execcmd = <<<EOF
123 927a988e jim-p
	global \$cpzone, \$config;
124 6c9ca678 Scott Ullrich
	require_once('/etc/inc/voucher.inc');
125 a18eeb51 bcyrill
	\$cpzone = "$cpzone";
126
	\$timeleft = voucher_auth("$voucher_received");
127 6c9ca678 Scott Ullrich
	\$toreturn = array();
128
	\$toreturn['timeleft'] = \$timeleft;
129 90df43c6 Ermal
	\$toreturn['voucher'] = array();
130 927a988e jim-p
	if (is_array(\$config['voucher'][\$cpzone]['roll'])) {
131
		\$toreturn['voucher']['roll'] = \$config['voucher'][\$cpzone]['roll'];
132
	}
133 6c9ca678 Scott Ullrich
134 fa3ab36a Scott Ullrich
EOF;
135 e3b0eeb2 PiBa-NL
	$rpc_client = new pfsense_xmlrpc_client();
136
	$rpc_client->setConnectionData($syncip, $port, $username, $password);
137 a8620841 PiBa-NL
	$resp = $rpc_client->xmlrpc_exec_php($execcmd);
138 179377b0 robjarsen
139 79262830 Phil Davis
	if (!is_array($config['voucher'])) {
140 90df43c6 Ermal
		$config['voucher'] = array();
141 79262830 Phil Davis
	}
142 62f96568 Ermal
143 200728c9 Renato Botelho
	if (is_array($resp['voucher']['roll'])) {
144
		$config['voucher'][$cpzone]['roll'] = $resp['voucher']['roll'];
145 1579e70f Phil Davis
		write_config(sprintf(gettext('Captive Portal Voucher database synchronized with %1$s:%2$s'), $syncip, $port));
146 b4792bf8 Ermal
		voucher_configure_zone(true);
147 200728c9 Renato Botelho
		unset($resp['voucher']);
148
	} else if (!isset($resp['timeleft'])) {
149 927a988e jim-p
		return 0;
150 79262830 Phil Davis
	}
151 f5c05fcc Ermal
152 200728c9 Renato Botelho
	return $resp['timeleft'];
153 fa3ab36a Scott Ullrich
}
154
155 05771a24 Ermal
function voucher_expire($voucher_received) {
156 abaa7feb Ermal LUÇI
	global $g, $config, $cpzone, $cpzoneid;
157 05771a24 Ermal
158
	// XMLRPC Call over to the master Voucher node
159 b8963db6 Renato Botelho
	if (xmlrpc_sync_voucher_details($syncip, $syncport,
160
	    $vouchersyncusername, $syncpass)) {
161
		xmlrpc_sync_voucher_expire($voucher_received, $syncip,
162
		    $syncport, $syncpass, $vouchersyncusername);
163 05771a24 Ermal
	}
164
165 90df43c6 Ermal
	$voucherlck = lock("voucher{$cpzone}", LOCK_EX);
166
167 05771a24 Ermal
	// read rolls into assoc array with rollid as key and minutes as value
168
	$tickets_per_roll = array();
169
	$minutes_per_roll = array();
170 b4792bf8 Ermal
	if (is_array($config['voucher'][$cpzone]['roll'])) {
171
		foreach ($config['voucher'][$cpzone]['roll'] as $rollent) {
172 05771a24 Ermal
			$tickets_per_roll[$rollent['number']] = $rollent['count'];
173
			$minutes_per_roll[$rollent['number']] = $rollent['minutes'];
174
		}
175
	}
176
177
	// split into an array. Useful for multiple vouchers given
178 79262830 Phil Davis
	$a_vouchers_received = preg_split("/[\t\n\r ]+/s", $voucher_received);
179 05771a24 Ermal
	$active_dirty = false;
180 5a6359ae bcyrill
	$unsetindexes = array();
181 2c85b316 Ermal
182 05771a24 Ermal
	// go through all received vouchers, check their valid and extract
183
	// Roll# and Ticket# using the external readvoucher binary
184
	foreach ($a_vouchers_received as $voucher) {
185
		$v = escapeshellarg($voucher);
186 9fcbc9ff Luiz Otavio O Souza
		if (strlen($voucher) < 5) {
187
			captiveportal_syslog("${voucher} invalid: Too short!");
188 05771a24 Ermal
			continue;   // seems too short to be a voucher!
189 79262830 Phil Davis
		}
190 05771a24 Ermal
191 15bec718 Ermal
		unset($output);
192
		$_gb = exec("/usr/local/bin/voucher -c {$g['varetc_path']}/voucher_{$cpzone}.cfg -k {$g['varetc_path']}/voucher_{$cpzone}.public -- $v", $output);
193
		list($status, $roll, $nr) = explode(" ", $output[0]);
194 05771a24 Ermal
		if ($status == "OK") {
195 79262830 Phil Davis
			// check if we have this ticket on a registered roll for this ticket
196 05771a24 Ermal
			if ($tickets_per_roll[$roll] && ($nr <= $tickets_per_roll[$roll])) {
197 79262830 Phil Davis
				// voucher is from a registered roll.
198
				if (!isset($active_vouchers[$roll])) {
199 05771a24 Ermal
					$active_vouchers[$roll] = voucher_read_active_db($roll);
200 79262830 Phil Davis
				}
201 05771a24 Ermal
				// valid voucher. Store roll# and ticket#
202
				if (!empty($active_vouchers[$roll][$voucher])) {
203
					$active_dirty = true;
204
					unset($active_vouchers[$roll][$voucher]);
205
				}
206
				// check if voucher already marked as used
207 79262830 Phil Davis
				if (!isset($bitstring[$roll])) {
208 05771a24 Ermal
					$bitstring[$roll] = voucher_read_used_db($roll);
209 79262830 Phil Davis
				}
210 05771a24 Ermal
				$pos = $nr >> 3; // divide by 8 -> octet
211
				$mask = 1 << ($nr % 8);
212
				// mark bit for this voucher as used
213 79262830 Phil Davis
				if (!(ord($bitstring[$roll][$pos]) & $mask)) {
214 05771a24 Ermal
					$bitstring[$roll][$pos] = chr(ord($bitstring[$roll][$pos]) | $mask);
215 79262830 Phil Davis
				}
216 05771a24 Ermal
				captiveportal_syslog("{$voucher} ({$roll}/{$nr}) forced to expire");
217 2c85b316 Ermal
218
				/* Check if this voucher has any active sessions */
219 26ee5aaf Ermal
				$cpentry = captiveportal_read_db("WHERE username = '{$voucher}'");
220 ea6cbc39 Gertjan
				if (!empty($cpentry) && !empty($cpentry[0])) {
221 086cf944 Phil Davis
					if (empty($cpzoneid) && !empty($config['captiveportal'][$cpzone])) {
222 abaa7feb Ermal LUÇI
						$cpzoneid = $config['captiveportal'][$cpzone]['zoneid'];
223 086cf944 Phil Davis
					}
224 ea6cbc39 Gertjan
					$cpentry = $cpentry[0];
225 086cf944 Phil Davis
					captiveportal_disconnect($cpentry, null, 13);
226
					captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "FORCLY TERMINATING VOUCHER {$voucher} SESSION");
227 5705c60a Renato Botelho
					$unsetindexes[] = $cpentry[5];
228 2c85b316 Ermal
				}
229 79262830 Phil Davis
			} else {
230 51a14c58 Phil Davis
				captiveportal_syslog(sprintf(gettext('%1$s (%2$s/%3$s): not found on any registered Roll'), $voucher, $roll, $nr));
231 79262830 Phil Davis
			}
232
		} else {
233 05771a24 Ermal
			// hmm, thats weird ... not what I expected
234 51a14c58 Phil Davis
			captiveportal_syslog(sprintf(gettext('%1$s invalid: %2$s!!'), $voucher, $output[0]));
235 79262830 Phil Davis
		}
236 05771a24 Ermal
	}
237
238
	// Refresh active DBs
239
	if ($active_dirty == true) {
240 79262830 Phil Davis
		foreach ($active_vouchers as $roll => $active) {
241 05771a24 Ermal
			voucher_write_active_db($roll, $active);
242 79262830 Phil Davis
		}
243 15bec718 Ermal
		unset($active_vouchers);
244 5ebe85e9 Ermal
245 f416763b Phil Davis
		/* Trigger a sync of the vouchers on config */
246 5ebe85e9 Ermal
		send_event("service sync vouchers");
247 05771a24 Ermal
	}
248
249
	// Write back the used DB's
250
	if (is_array($bitstring)) {
251
		foreach ($bitstring as $roll => $used) {
252 79262830 Phil Davis
			if (is_array($used)) {
253
				foreach ($used as $u) {
254 05771a24 Ermal
					voucher_write_used_db($roll, base64_encode($u));
255 79262830 Phil Davis
				}
256 05771a24 Ermal
			} else {
257
				voucher_write_used_db($roll, base64_encode($used));
258
			}
259
		}
260 15bec718 Ermal
		unset($bitstring);
261 05771a24 Ermal
	}
262
263
	unlock($voucherlck);
264
265 2c85b316 Ermal
	/* Write database */
266 79262830 Phil Davis
	if (!empty($unsetindexes)) {
267 26ee5aaf Ermal
		captiveportal_remove_entries($unsetindexes);
268 79262830 Phil Davis
	}
269 2c85b316 Ermal
270 05771a24 Ermal
	return true;
271
}
272
273 79262830 Phil Davis
/*
274 666bc4d1 Ermal
 * Authenticate a voucher and return the remaining time credit in minutes
275 336e3c1c Charlie
 * if $test is set, don't mark the voucher as used nor add it to the list
276
 * of active vouchers
277 666bc4d1 Ermal
 * If $test is set, simply test the voucher. Don't change anything
278
 * but return a more verbose error and result message back
279 336e3c1c Charlie
 */
280
function voucher_auth($voucher_received, $test = 0) {
281 b4792bf8 Ermal
	global $g, $config, $cpzone, $dbc;
282 336e3c1c Charlie
283 79262830 Phil Davis
	if (!isset($config['voucher'][$cpzone]['enable'])) {
284 1a863be2 Ermal
		return 0;
285 79262830 Phil Davis
	}
286 1a863be2 Ermal
287 6c9ca678 Scott Ullrich
	// XMLRPC Call over to the master Voucher node
288 b8963db6 Renato Botelho
	if (xmlrpc_sync_voucher_details($syncip, $syncport,
289
	    $vouchersyncusername, $syncpass)) {
290
		$remote_time_used = xmlrpc_sync_used_voucher($voucher_received,
291
		    $syncip, $syncport, $syncpass, $vouchersyncusername);
292 6c9ca678 Scott Ullrich
	}
293 fa3ab36a Scott Ullrich
294 90df43c6 Ermal
	$voucherlck = lock("voucher{$cpzone}", LOCK_EX);
295
296 7afb7ea9 Ermal
	// read rolls into assoc array with rollid as key and minutes as value
297
	$tickets_per_roll = array();
298
	$minutes_per_roll = array();
299 b4792bf8 Ermal
	if (is_array($config['voucher'][$cpzone]['roll'])) {
300
		foreach ($config['voucher'][$cpzone]['roll'] as $rollent) {
301 7afb7ea9 Ermal
			$tickets_per_roll[$rollent['number']] = $rollent['count'];
302
			$minutes_per_roll[$rollent['number']] = $rollent['minutes'];
303
		}
304
	}
305 336e3c1c Charlie
306 05771a24 Ermal
	// split into an array. Useful for multiple vouchers given
307 79262830 Phil Davis
	$a_vouchers_received = preg_split("/[\t\n\r ]+/s", $voucher_received);
308 05771a24 Ermal
	$error = 0;
309
	$test_result = array();     // used to display for voucher test option in GUI
310
	$total_minutes = 0;
311
	$first_voucher = "";
312
	$first_voucher_roll = 0;
313
314
	// go through all received vouchers, check their valid and extract
315
	// Roll# and Ticket# using the external readvoucher binary
316
	foreach ($a_vouchers_received as $voucher) {
317
		$v = escapeshellarg($voucher);
318 9fcbc9ff Luiz Otavio O Souza
		if (strlen($voucher) < 5) {
319 51a14c58 Phil Davis
			$voucher_err_text = sprintf(gettext("%s invalid: Too short!"), $voucher);
320
			$test_result[] = $voucher_err_text;
321
			captiveportal_syslog($voucher_err_text);
322 b08758c3 jim-p
			$error++;
323 05771a24 Ermal
			continue;   // seems too short to be a voucher!
324 79262830 Phil Davis
		}
325 05771a24 Ermal
326 b4792bf8 Ermal
		$result = exec("/usr/local/bin/voucher -c {$g['varetc_path']}/voucher_{$cpzone}.cfg -k {$g['varetc_path']}/voucher_{$cpzone}.public -- $v");
327 05771a24 Ermal
		list($status, $roll, $nr) = explode(" ", $result);
328
		if ($status == "OK") {
329
			if (!$first_voucher) {
330
				// store first voucher. Thats the one we give the timecredit
331
				$first_voucher = $voucher;
332
				$first_voucher_roll = $roll;
333
			}
334 79262830 Phil Davis
			// check if we have this ticket on a registered roll for this ticket
335 05771a24 Ermal
			if ($tickets_per_roll[$roll] && ($nr <= $tickets_per_roll[$roll])) {
336 79262830 Phil Davis
				// voucher is from a registered roll.
337
				if (!isset($active_vouchers[$roll])) {
338 05771a24 Ermal
					$active_vouchers[$roll] = voucher_read_active_db($roll);
339 79262830 Phil Davis
				}
340 05771a24 Ermal
				// valid voucher. Store roll# and ticket#
341
				if (!empty($active_vouchers[$roll][$voucher])) {
342 086cf944 Phil Davis
					list($timestamp, $minutes) = explode(",", $active_vouchers[$roll][$voucher]);
343 05771a24 Ermal
					// we have an already active voucher here.
344
					$remaining = intval((($timestamp + (60*$minutes)) - time())/60);
345 d8012adb Vinicius Coque
					$test_result[] = sprintf(gettext('%1$s (%2$s/%3$s) active and good for %4$d Minutes'), $voucher, $roll, $nr, $remaining);
346 05771a24 Ermal
					$total_minutes += $remaining;
347
				} else {
348
					// voucher not used. Check if ticket Id is on the roll (not too high)
349
					// and if the ticket is marked used.
350
					// check if voucher already marked as used
351 79262830 Phil Davis
					if (!isset($bitstring[$roll])) {
352 05771a24 Ermal
						$bitstring[$roll] = voucher_read_used_db($roll);
353 79262830 Phil Davis
					}
354 05771a24 Ermal
					$pos = $nr >> 3; // divide by 8 -> octet
355
					$mask = 1 << ($nr % 8);
356
					if (ord($bitstring[$roll][$pos]) & $mask) {
357 51a14c58 Phil Davis
						$voucher_err_text = sprintf(gettext('%1$s (%2$s/%3$s) already used and expired'), $voucher, $roll, $nr);
358
						$test_result[] = $voucher_err_text;
359
						captiveportal_syslog($voucher_err_text);
360 05771a24 Ermal
						$total_minutes = -1;    // voucher expired
361
						$error++;
362
					} else {
363
						// mark bit for this voucher as used
364
						$bitstring[$roll][$pos] = chr(ord($bitstring[$roll][$pos]) | $mask);
365 51a14c58 Phil Davis
						$test_result[] = sprintf(gettext('%1$s (%2$s/%3$s) good for %4$s Minutes'), $voucher, $roll, $nr, $minutes_per_roll[$roll]);
366 05771a24 Ermal
						$total_minutes += $minutes_per_roll[$roll];
367
					}
368
				}
369
			} else {
370 51a14c58 Phil Davis
				$voucher_err_text = sprintf(gettext('%1$s (%2$s/%3$s): not found on any registered Roll'), $voucher, $roll, $nr);
371
				$test_result[] = $voucher_err_text;
372
				captiveportal_syslog($voucher_err_text);
373 05771a24 Ermal
			}
374
		} else {
375
			// hmm, thats weird ... not what I expected
376 51a14c58 Phil Davis
			$voucher_err_text = sprintf(gettext('%1$s invalid: %2$s !!'), $voucher, $result);
377
			$test_result[] = $voucher_err_text;
378
			captiveportal_syslog($voucher_err_text);
379 05771a24 Ermal
			$error++;
380
		}
381
	}
382 336e3c1c Charlie
383 05771a24 Ermal
	// if this was a test call, we're done. Return the result.
384
	if ($test) {
385
		if ($error) {
386 d8012adb Vinicius Coque
			$test_result[] = gettext("Access denied!");
387 05771a24 Ermal
		} else {
388 086cf944 Phil Davis
			$test_result[] = sprintf(gettext("Access granted for %d Minutes in total."), $total_minutes);
389 05771a24 Ermal
		}
390
		unlock($voucherlck);
391 336e3c1c Charlie
392 05771a24 Ermal
		return $test_result;
393
	}
394 336e3c1c Charlie
395 05771a24 Ermal
	// if we had an error (one of the vouchers is invalid), return 0.
396
	// Discussion: we could return the time remaining for good vouchers, but then
397
	// the user wouldn't know that he used at least one invalid voucher.
398
	if ($error) {
399 830c33be Scott Ullrich
		unlock($voucherlck);
400 79262830 Phil Davis
		if ($total_minutes > 0) {   // probably not needed, but want to make sure
401 05771a24 Ermal
			$total_minutes = 0;     // we only report -1 (expired) or 0 (no access)
402 79262830 Phil Davis
		}
403 05771a24 Ermal
		return $total_minutes;       // well, at least one voucher had errors. Say NO ACCESS
404
	}
405 336e3c1c Charlie
406 6c9ca678 Scott Ullrich
	// If we did a XMLRPC sync earlier check the timeleft
407 62f96568 Ermal
	if (!empty($config['voucher'][$cpzone]['vouchersyncdbip'])) {
408 79262830 Phil Davis
		if (!is_null($remote_time_used)) {
409 62f96568 Ermal
			$total_minutes = $remote_time_used;
410 79262830 Phil Davis
		} else if ($remote_time_used < $total_minutes) {
411 f3512fca jim-p
			$total_minutes -= $remote_time_used;
412 79262830 Phil Davis
		}
413 62f96568 Ermal
	}
414 830c33be Scott Ullrich
415 05771a24 Ermal
	// All given vouchers were valid and this isn't simply a test.
416
	// Write back the used DB's
417 c14d9967 Scott Ullrich
	if (is_array($bitstring)) {
418
		foreach ($bitstring as $roll => $used) {
419 79262830 Phil Davis
			if (is_array($used)) {
420
				foreach ($used as $u) {
421 c14d9967 Scott Ullrich
					voucher_write_used_db($roll, base64_encode($u));
422 79262830 Phil Davis
				}
423 c14d9967 Scott Ullrich
			} else {
424
				voucher_write_used_db($roll, base64_encode($used));
425
			}
426
		}
427
	}
428 336e3c1c Charlie
429 05771a24 Ermal
	// Active DB: we only add the first voucher if multiple given
430
	// and give that one all the time credit. This allows the user to logout and
431
	// log in later using just the first voucher. It also keeps username limited
432
	// to one voucher and that voucher shows the correct time credit in 'active vouchers'
433
	if (!empty($active_vouchers[$first_voucher_roll][$first_voucher])) {
434
		list($timestamp, $minutes) = explode(",", $active_vouchers[$first_voucher_roll][$first_voucher]);
435
	} else {
436
		$timestamp = time();    // new voucher
437
		$minutes = $total_minutes;
438
	}
439 336e3c1c Charlie
440 05771a24 Ermal
	$active_vouchers[$first_voucher_roll][$first_voucher] = "$timestamp,$minutes";
441 80b86de5 Ermal
	voucher_write_active_db($first_voucher_roll, $active_vouchers[$first_voucher_roll]);
442 336e3c1c Charlie
443 f416763b Phil Davis
	/* Trigger a sync of the vouchers on config */
444 5ebe85e9 Ermal
	send_event("service sync vouchers");
445
446 05771a24 Ermal
	unlock($voucherlck);
447 336e3c1c Charlie
448 05771a24 Ermal
	return $total_minutes;
449 336e3c1c Charlie
}
450
451 351b6990 Ermal
function voucher_configure($sync = false) {
452 b4792bf8 Ermal
	global $config, $g, $cpzone;
453 336e3c1c Charlie
454 b4792bf8 Ermal
	if (is_array($config['voucher'])) {
455
		foreach ($config['voucher'] as $voucherzone => $vcfg) {
456 79262830 Phil Davis
			if (platform_booting()) {
457
				echo gettext("Enabling voucher support... ");
458
			}
459 b4792bf8 Ermal
			$cpzone = $voucherzone;
460 abf421ce Ermal
			$error = voucher_configure_zone($sync);
461 285ef132 Ermal LUÇI
			if (platform_booting()) {
462 79262830 Phil Davis
				if ($error) {
463 abf421ce Ermal
					echo "error\n";
464 79262830 Phil Davis
				} else {
465 abf421ce Ermal
					echo "done\n";
466 79262830 Phil Davis
				}
467 abf421ce Ermal
			}
468 b4792bf8 Ermal
		}
469
	}
470
}
471
472
function voucher_configure_zone($sync = false) {
473
	global $config, $g, $cpzone;
474
475 79262830 Phil Davis
	if (!isset($config['voucher'][$cpzone]['enable'])) {
476 eaca40df Ermal
		return 0;
477 79262830 Phil Davis
	}
478 336e3c1c Charlie
479 79262830 Phil Davis
	if ($sync == true) {
480
		captiveportal_syslog("Writing voucher db from sync data...");
481
	}
482 336e3c1c Charlie
483 b4792bf8 Ermal
	$voucherlck = lock("voucher{$cpzone}", LOCK_EX);
484 eaca40df Ermal
485 79262830 Phil Davis
	/* write public key used to verify vouchers */
486
	$pubkey = base64_decode($config['voucher'][$cpzone]['publickey']);
487
	$fd = fopen("{$g['varetc_path']}/voucher_{$cpzone}.public", "w");
488
	if (!$fd) {
489
		captiveportal_syslog("Voucher error: cannot write voucher.public\n");
490
		unlock($voucherlck);
491
		return 1;
492
	}
493
	fwrite($fd, $pubkey);
494
	fclose($fd);
495
	@chmod("{$g['varetc_path']}/voucher_{$cpzone}.public", 0600);
496
497
	/* write config file used by voucher binary to decode vouchers */
498
	$fd = fopen("{$g['varetc_path']}/voucher_{$cpzone}.cfg", "w");
499
	if (!$fd) {
500
		printf(gettext("Error: cannot write voucher.cfg") . "\n");
501
		unlock($voucherlck);
502
		return 1;
503
	}
504
	fwrite($fd, "{$config['voucher'][$cpzone]['rollbits']},{$config['voucher'][$cpzone]['ticketbits']},{$config['voucher'][$cpzone]['checksumbits']},{$config['voucher'][$cpzone]['magic']},{$config['voucher'][$cpzone]['charset']}\n");
505
	fclose($fd);
506
	@chmod("{$g['varetc_path']}/voucher_{$cpzone}.cfg", 0600);
507 c4ea3691 Ermal
	unlock($voucherlck);
508 336e3c1c Charlie
509 79262830 Phil Davis
	if ((platform_booting() || $sync == true) && is_array($config['voucher'][$cpzone]['roll'])) {
510 336e3c1c Charlie
511 b4792bf8 Ermal
		$voucherlck = lock("voucher{$cpzone}", LOCK_EX);
512 336e3c1c Charlie
513 79262830 Phil Davis
		// create active and used DB per roll on ramdisk from config
514
		foreach ($config['voucher'][$cpzone]['roll'] as $rollent) {
515
516
			$roll = $rollent['number'];
517 351b8519 Luiz Otavio O Souza
			$len = ($rollent['count'] >> 3) + 1;
518 4e322e2c Phil Davis
			if (strlen(base64_decode($rollent['used'])) != $len) {
519 351b8519 Luiz Otavio O Souza
				$rollent['used'] = base64_encode(str_repeat("\000", $len));
520 4e322e2c Phil Davis
			}
521 79262830 Phil Davis
			voucher_write_used_db($roll, $rollent['used']);
522
			$minutes = $rollent['minutes'];
523
			$active_vouchers = array();
524
			$a_active = &$rollent['active'];
525
			if (is_array($a_active)) {
526
				foreach ($a_active as $activent) {
527
					$voucher = $activent['voucher'];
528
					$timestamp = $activent['timestamp'];
529
					$minutes = $activent['minutes'];
530
					// its tempting to check for expired timestamps, but during
531
					// bootup, we most likely don't have the correct time.
532
					$active_vouchers[$voucher] = "$timestamp,$minutes";
533
				}
534
			}
535
			voucher_write_active_db($roll, $active_vouchers);
536
		}
537 c4ea3691 Ermal
538
		unlock($voucherlck);
539 79262830 Phil Davis
	}
540 eaca40df Ermal
541
	return 0;
542 336e3c1c Charlie
}
543
544 79262830 Phil Davis
/* write bitstring of used vouchers to ramdisk.
545 336e3c1c Charlie
 * Bitstring must already be base64_encoded!
546
 */
547
function voucher_write_used_db($roll, $vdb) {
548 b4792bf8 Ermal
	global $g, $cpzone;
549 666bc4d1 Ermal
550 b4792bf8 Ermal
	$fd = fopen("{$g['vardb_path']}/voucher_{$cpzone}_used_$roll.db", "w");
551 666bc4d1 Ermal
	if ($fd) {
552
		fwrite($fd, $vdb . "\n");
553
		fclose($fd);
554 79262830 Phil Davis
	} else {
555 51a14c58 Phil Davis
		voucher_log(LOG_ERR, sprintf(gettext('cant write %1$s/voucher_%2$s_used_%3$s.db'), $g['vardb_path'], $cpzone, $roll));
556 79262830 Phil Davis
	}
557 336e3c1c Charlie
}
558
559
/* return assoc array of active vouchers with activation timestamp
560 79262830 Phil Davis
 * voucher is index.
561 336e3c1c Charlie
 */
562
function voucher_read_active_db($roll) {
563 b4792bf8 Ermal
	global $g, $cpzone;
564 666bc4d1 Ermal
565
	$active = array();
566
	$dirty = 0;
567 b4792bf8 Ermal
	$file = "{$g['vardb_path']}/voucher_{$cpzone}_active_$roll.db";
568 666bc4d1 Ermal
	if (file_exists($file)) {
569
		$fd = fopen($file, "r");
570
		if ($fd) {
571
			while (!feof($fd)) {
572
				$line = trim(fgets($fd));
573
				if ($line) {
574 086cf944 Phil Davis
					list($voucher, $timestamp, $minutes) = explode(",", $line); // voucher,timestamp
575 79262830 Phil Davis
					if ((($timestamp + (60*$minutes)) - time()) > 0) {
576 666bc4d1 Ermal
						$active[$voucher] = "$timestamp,$minutes";
577 79262830 Phil Davis
					} else {
578 666bc4d1 Ermal
						$dirty=1;
579 79262830 Phil Davis
					}
580 666bc4d1 Ermal
				}
581
			}
582
			fclose($fd);
583 5ebe85e9 Ermal
			if ($dirty) { // if we found expired entries, lets save our snapshot
584 666bc4d1 Ermal
				voucher_write_active_db($roll, $active);
585 5ebe85e9 Ermal
586 f416763b Phil Davis
				/* Trigger a sync of the vouchers on config */
587 5ebe85e9 Ermal
				send_event("service sync vouchers");
588
			}
589 666bc4d1 Ermal
		}
590
	}
591
	return $active;
592 336e3c1c Charlie
}
593
594
/* store array of active vouchers back to DB */
595
function voucher_write_active_db($roll, $active) {
596 79262830 Phil Davis
	global $g, $cpzone;
597 336e3c1c Charlie
598 79262830 Phil Davis
	if (!is_array($active)) {
599 05771a24 Ermal
		return;
600 79262830 Phil Davis
	}
601
	$fd = fopen("{$g['vardb_path']}/voucher_{$cpzone}_active_$roll.db", "w");
602
	if ($fd) {
603
		foreach ($active as $voucher => $value) {
604
			fwrite($fd, "$voucher,$value\n");
605
		}
606
		fclose($fd);
607
	}
608 336e3c1c Charlie
}
609
610
/* return how many vouchers are marked used on a roll */
611
function voucher_used_count($roll) {
612 79262830 Phil Davis
	global $g, $cpzone;
613
614
	$bitstring = voucher_read_used_db($roll);
615
	$max = strlen($bitstring) * 8;
616
	$used = 0;
617
	for ($i = 1; $i <= $max; $i++) {
618
		// check if ticket already used or not.
619
		$pos = $i >> 3;            // divide by 8 -> octet
620
		$mask = 1 << ($i % 8);  // mask to test bit in octet
621
		if (ord($bitstring[$pos]) & $mask) {
622
			$used++;
623
		}
624
	}
625
	unset($bitstring);
626
627
	return $used;
628 336e3c1c Charlie
}
629
630
function voucher_read_used_db($roll) {
631 79262830 Phil Davis
	global $g, $cpzone;
632
633
	$vdb = "";
634
	$file = "{$g['vardb_path']}/voucher_{$cpzone}_used_$roll.db";
635
	if (file_exists($file)) {
636
		$fd = fopen($file, "r");
637
		if ($fd) {
638
			$vdb = trim(fgets($fd));
639
			fclose($fd);
640
		} else {
641 51a14c58 Phil Davis
			voucher_log(LOG_ERR, sprintf(gettext('cant read %1$s/voucher_%2$s_used_%3$s.db'), $g['vardb_path'], $cpzone, $roll));
642 79262830 Phil Davis
		}
643
	}
644
	return base64_decode($vdb);
645 336e3c1c Charlie
}
646
647
function voucher_unlink_db($roll) {
648 79262830 Phil Davis
	global $g, $cpzone;
649
	@unlink("{$g['vardb_path']}/voucher_{$cpzone}_used_$roll.db");
650
	@unlink("{$g['vardb_path']}/voucher_{$cpzone}_active_$roll.db");
651 336e3c1c Charlie
}
652
653
/* we share the log with captiveportal for now */
654
function voucher_log($priority, $message) {
655
656 79262830 Phil Davis
	$message = trim($message);
657
	openlog("logportalauth", LOG_PID, LOG_LOCAL4);
658 086cf944 Phil Davis
	syslog($priority, sprintf(gettext("Voucher: %s"), $message));
659 79262830 Phil Davis
	closelog();
660 336e3c1c Charlie
}
661
662
/* Save active and used voucher DB into XML config and write it to flash
663 5ebe85e9 Ermal
 * Called during reboot -> system_reboot_cleanup() and every active voucher change
664 336e3c1c Charlie
 */
665
function voucher_save_db_to_config() {
666 79262830 Phil Davis
	global $config, $g, $cpzone;
667 b4792bf8 Ermal
668
	if (is_array($config['voucher'])) {
669 573ae2d1 Chris Buechler
		foreach ($config['voucher'] as $voucherzone => $vcfg) {
670 b4792bf8 Ermal
			$cpzone = $voucherzone;
671
			voucher_save_db_to_config_zone();
672
		}
673
	}
674
}
675
676 52bb3619 Cyrill Bannwart
function voucher_save_db_to_config_zone() {
677 79262830 Phil Davis
	global $config, $g, $cpzone;
678 336e3c1c Charlie
679 79262830 Phil Davis
	if (!isset($config['voucher'][$cpzone]['enable'])) {
680
		return;   // no vouchers or don't want to save DB's
681
	}
682
683
	if (!is_array($config['voucher'][$cpzone]['roll'])) {
684
		return;
685
	}
686
687
	$voucherlck = lock("voucher{$cpzone}", LOCK_EX);
688 c65c3a5d Ermal
689 79262830 Phil Davis
	// walk all active rolls and save runtime DB's to flash
690
	$a_roll = &$config['voucher'][$cpzone]['roll'];
691
	while (list($key, $value) = each($a_roll)) {
692
		$rollent = &$a_roll[$key];
693
		$roll = $rollent['number'];
694
		$bitmask = voucher_read_used_db($roll);
695
		$rollent['used'] = base64_encode($bitmask);
696
		$active_vouchers = voucher_read_active_db($roll);
697
		$db = array();
698 4d5bbdfb Scott Ullrich
		$dbi = 1;
699 79262830 Phil Davis
		foreach ($active_vouchers as $voucher => $line) {
700 086cf944 Phil Davis
			list($timestamp, $minutes) = explode(",", $line);
701 79262830 Phil Davis
			$activent['voucher'] = $voucher;
702
			$activent['timestamp'] = $timestamp;
703
			$activent['minutes'] = $minutes;
704
			$db["v{$dbi}"] = $activent;
705
			$dbi++;
706
		}
707
		$rollent['active'] = $db;
708
		unset($active_vouchers);
709
	}
710
711
	unlock($voucherlck);
712
713 51a14c58 Phil Davis
	write_config(gettext("Syncing vouchers"));
714 79262830 Phil Davis
	return;
715 336e3c1c Charlie
}
716
717 2ee5fe9b Ermal Lu?i
?>