Project

General

Profile

Download (18.7 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 38809d47 Renato Botelho do Couto
 * Copyright (c) 2007-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8 8f2f85c3 Luiz Otavio O Souza
 * Copyright (c) 2014-2022 Rubicon Communications, LLC (Netgate)
9 c5d81585 Renato Botelho
 * Copyright (c) 2007 Marcel Wiget <mwiget@mac.com>
10 ac24dc24 Renato Botelho
 * All rights reserved.
11
 *
12
 * originally part of m0n0wall (http://m0n0.ch/wall)
13 c5d81585 Renato Botelho
 * Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>.
14 ac24dc24 Renato Botelho
 * All rights reserved.
15
 *
16 b12ea3fb Renato Botelho
 * Licensed under the Apache License, Version 2.0 (the "License");
17
 * you may not use this file except in compliance with the License.
18
 * You may obtain a copy of the License at
19 ac24dc24 Renato Botelho
 *
20 b12ea3fb Renato Botelho
 * http://www.apache.org/licenses/LICENSE-2.0
21 ac24dc24 Renato Botelho
 *
22 b12ea3fb Renato Botelho
 * Unless required by applicable law or agreed to in writing, software
23
 * distributed under the License is distributed on an "AS IS" BASIS,
24
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25
 * See the License for the specific language governing permissions and
26
 * limitations under the License.
27 ac24dc24 Renato Botelho
 */
28 523855b0 Scott Ullrich
29 336e3c1c Charlie
/* include all configuration functions */
30 79262830 Phil Davis
if (!function_exists('captiveportal_syslog')) {
31 4e8d55dd Scott Ullrich
	require_once("captiveportal.inc");
32 79262830 Phil Davis
}
33 336e3c1c Charlie
34 24600471 Augustin-FL
function captiveportal_xmlrpc_sync_get_details(&$syncip, &$port, &$username, &$password, $carp_loop = false) {
35 65a51647 Augustin-FL
	global $config, $cpzone;
36 b8963db6 Renato Botelho
37 24600471 Augustin-FL
	if (isset($config['captiveportal'][$cpzone]['enablebackwardsync']) && !$carp_loop
38
	    && captiveportal_ha_is_node_in_backup_mode($cpzone)) {
39 06ef0830 Augustin-FL
		$syncip = $config['captiveportal'][$cpzone]['backwardsyncip'];
40
		$username = $config['captiveportal'][$cpzone]['backwardsyncuser'];
41
		$password = $config['captiveportal'][$cpzone]['backwardsyncpassword'];
42
		$port = $config['system']['webgui']['port'];
43
		if (empty($port)) { // if port is empty lets rely on the protocol selection
44
			if ($config['system']['webgui']['protocol'] == "http") {
45
				$port = "80";
46
			} else {
47
				$port = "443";
48
			}
49
		}
50 b8963db6 Renato Botelho
		return true;
51
	}
52
53
	if (!is_array($config['hasync']) ||
54
	    empty($config['hasync']['synchronizetoip']) ||
55 24600471 Augustin-FL
	    $config['hasync']['synchronizecaptiveportal'] == "" ||
56
	    $carp_loop == true) {
57 b8963db6 Renato Botelho
		return false;
58
	}
59
60
	$syncip = $config['hasync']['synchronizetoip'];
61
	$password = $config['hasync']['password'];
62
	if (empty($config['hasync']['username'])) {
63
		$username = "admin";
64
	} else {
65
		$username = $config['hasync']['username'];
66
	}
67
68
	/* if port is empty lets rely on the protocol selection */
69
	$port = $config['system']['webgui']['port'];
70
	if (empty($port)) {
71
		if ($config['system']['webgui']['protocol'] == "http") {
72
			$port = "80";
73
		} else {
74
			$port = "443";
75
		}
76
	}
77
78
	return true;
79
}
80
81 6bfb5b9e Augustin-FL
function voucher_expire($voucher_received, $carp_loop = false) {
82 abaa7feb Ermal LUÇI
	global $g, $config, $cpzone, $cpzoneid;
83 05771a24 Ermal
84 90df43c6 Ermal
	$voucherlck = lock("voucher{$cpzone}", LOCK_EX);
85
86 05771a24 Ermal
	// read rolls into assoc array with rollid as key and minutes as value
87
	$tickets_per_roll = array();
88
	$minutes_per_roll = array();
89 b4792bf8 Ermal
	if (is_array($config['voucher'][$cpzone]['roll'])) {
90
		foreach ($config['voucher'][$cpzone]['roll'] as $rollent) {
91 05771a24 Ermal
			$tickets_per_roll[$rollent['number']] = $rollent['count'];
92
			$minutes_per_roll[$rollent['number']] = $rollent['minutes'];
93
		}
94
	}
95
96
	// split into an array. Useful for multiple vouchers given
97 79262830 Phil Davis
	$a_vouchers_received = preg_split("/[\t\n\r ]+/s", $voucher_received);
98 05771a24 Ermal
	$active_dirty = false;
99 5a6359ae bcyrill
	$unsetindexes = array();
100 2c85b316 Ermal
101 05771a24 Ermal
	// go through all received vouchers, check their valid and extract
102
	// Roll# and Ticket# using the external readvoucher binary
103
	foreach ($a_vouchers_received as $voucher) {
104
		$v = escapeshellarg($voucher);
105 9fcbc9ff Luiz Otavio O Souza
		if (strlen($voucher) < 5) {
106
			captiveportal_syslog("${voucher} invalid: Too short!");
107 05771a24 Ermal
			continue;   // seems too short to be a voucher!
108 79262830 Phil Davis
		}
109 05771a24 Ermal
110 15bec718 Ermal
		unset($output);
111
		$_gb = exec("/usr/local/bin/voucher -c {$g['varetc_path']}/voucher_{$cpzone}.cfg -k {$g['varetc_path']}/voucher_{$cpzone}.public -- $v", $output);
112
		list($status, $roll, $nr) = explode(" ", $output[0]);
113 05771a24 Ermal
		if ($status == "OK") {
114 79262830 Phil Davis
			// check if we have this ticket on a registered roll for this ticket
115 05771a24 Ermal
			if ($tickets_per_roll[$roll] && ($nr <= $tickets_per_roll[$roll])) {
116 79262830 Phil Davis
				// voucher is from a registered roll.
117
				if (!isset($active_vouchers[$roll])) {
118 05771a24 Ermal
					$active_vouchers[$roll] = voucher_read_active_db($roll);
119 79262830 Phil Davis
				}
120 05771a24 Ermal
				// valid voucher. Store roll# and ticket#
121
				if (!empty($active_vouchers[$roll][$voucher])) {
122
					$active_dirty = true;
123
					unset($active_vouchers[$roll][$voucher]);
124
				}
125
				// check if voucher already marked as used
126 79262830 Phil Davis
				if (!isset($bitstring[$roll])) {
127 05771a24 Ermal
					$bitstring[$roll] = voucher_read_used_db($roll);
128 79262830 Phil Davis
				}
129 05771a24 Ermal
				$pos = $nr >> 3; // divide by 8 -> octet
130
				$mask = 1 << ($nr % 8);
131
				// mark bit for this voucher as used
132 79262830 Phil Davis
				if (!(ord($bitstring[$roll][$pos]) & $mask)) {
133 05771a24 Ermal
					$bitstring[$roll][$pos] = chr(ord($bitstring[$roll][$pos]) | $mask);
134 79262830 Phil Davis
				}
135 05771a24 Ermal
				captiveportal_syslog("{$voucher} ({$roll}/{$nr}) forced to expire");
136 2c85b316 Ermal
137
				/* Check if this voucher has any active sessions */
138 26ee5aaf Ermal
				$cpentry = captiveportal_read_db("WHERE username = '{$voucher}'");
139 ea6cbc39 Gertjan
				if (!empty($cpentry) && !empty($cpentry[0])) {
140 086cf944 Phil Davis
					if (empty($cpzoneid) && !empty($config['captiveportal'][$cpzone])) {
141 abaa7feb Ermal LUÇI
						$cpzoneid = $config['captiveportal'][$cpzone]['zoneid'];
142 086cf944 Phil Davis
					}
143 ea6cbc39 Gertjan
					$cpentry = $cpentry[0];
144 eb43c5b1 Augustin FL
					captiveportal_disconnect($cpentry, 13);
145 086cf944 Phil Davis
					captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "FORCLY TERMINATING VOUCHER {$voucher} SESSION");
146 5705c60a Renato Botelho
					$unsetindexes[] = $cpentry[5];
147 2c85b316 Ermal
				}
148 79262830 Phil Davis
			} else {
149 51a14c58 Phil Davis
				captiveportal_syslog(sprintf(gettext('%1$s (%2$s/%3$s): not found on any registered Roll'), $voucher, $roll, $nr));
150 79262830 Phil Davis
			}
151
		} else {
152 05771a24 Ermal
			// hmm, thats weird ... not what I expected
153 51a14c58 Phil Davis
			captiveportal_syslog(sprintf(gettext('%1$s invalid: %2$s!!'), $voucher, $output[0]));
154 79262830 Phil Davis
		}
155 05771a24 Ermal
	}
156
157
	// Refresh active DBs
158
	if ($active_dirty == true) {
159 79262830 Phil Davis
		foreach ($active_vouchers as $roll => $active) {
160 05771a24 Ermal
			voucher_write_active_db($roll, $active);
161 79262830 Phil Davis
		}
162 896889e9 Augustin-FL
		/* perform in-use vouchers expiration using check_reload_status */
163 5ebe85e9 Ermal
		send_event("service sync vouchers");
164 6bfb5b9e Augustin-FL
	} else {
165
		$active_vouchers = array();
166 05771a24 Ermal
	}
167
168
	// Write back the used DB's
169
	if (is_array($bitstring)) {
170
		foreach ($bitstring as $roll => $used) {
171 79262830 Phil Davis
			if (is_array($used)) {
172
				foreach ($used as $u) {
173 05771a24 Ermal
					voucher_write_used_db($roll, base64_encode($u));
174 79262830 Phil Davis
				}
175 05771a24 Ermal
			} else {
176
				voucher_write_used_db($roll, base64_encode($used));
177
			}
178
		}
179
	}
180
181
	unlock($voucherlck);
182
183 2c85b316 Ermal
	/* Write database */
184 79262830 Phil Davis
	if (!empty($unsetindexes)) {
185 26ee5aaf Ermal
		captiveportal_remove_entries($unsetindexes);
186 79262830 Phil Davis
	}
187 2c85b316 Ermal
188 6bfb5b9e Augustin-FL
	// XMLRPC Call over to the other node
189
	if (captiveportal_xmlrpc_sync_get_details($syncip, $syncport,
190
	    $syncuser, $syncpass, $carp_loop)) {
191
		$rpc_client = new pfsense_xmlrpc_client();
192
		$rpc_client->setConnectionData($syncip, $syncport, $syncuser, $syncpass);
193
		$rpc_client->set_noticefile("CaptivePortalVouchersSync");
194
		$arguments = array(
195
			'active_and_used_vouchers_bitmasks' => $bitstring,
196
			'active_vouchers' => $active_vouchers
197
		);
198
199
		$rpc_client->xmlrpc_method('captive_portal_sync',
200
			array(
201
				'op' => 'write_vouchers',
202
				'zone' => $cpzone,
203
				'arguments' => base64_encode(serialize($arguments))
204
			)
205
		);
206
	}
207 05771a24 Ermal
	return true;
208
}
209
210 79262830 Phil Davis
/*
211 666bc4d1 Ermal
 * Authenticate a voucher and return the remaining time credit in minutes
212 336e3c1c Charlie
 * if $test is set, don't mark the voucher as used nor add it to the list
213
 * of active vouchers
214 666bc4d1 Ermal
 * If $test is set, simply test the voucher. Don't change anything
215
 * but return a more verbose error and result message back
216 336e3c1c Charlie
 */
217 318e3f81 Augustin-FL
function voucher_auth($voucher_received, $test = 0, $carp_loop = false) {
218 b4792bf8 Ermal
	global $g, $config, $cpzone, $dbc;
219 336e3c1c Charlie
220 79262830 Phil Davis
	if (!isset($config['voucher'][$cpzone]['enable'])) {
221 1a863be2 Ermal
		return 0;
222 79262830 Phil Davis
	}
223 1a863be2 Ermal
224 90df43c6 Ermal
	$voucherlck = lock("voucher{$cpzone}", LOCK_EX);
225
226 7afb7ea9 Ermal
	// read rolls into assoc array with rollid as key and minutes as value
227
	$tickets_per_roll = array();
228
	$minutes_per_roll = array();
229 b4792bf8 Ermal
	if (is_array($config['voucher'][$cpzone]['roll'])) {
230
		foreach ($config['voucher'][$cpzone]['roll'] as $rollent) {
231 7afb7ea9 Ermal
			$tickets_per_roll[$rollent['number']] = $rollent['count'];
232
			$minutes_per_roll[$rollent['number']] = $rollent['minutes'];
233
		}
234
	}
235 336e3c1c Charlie
236 05771a24 Ermal
	// split into an array. Useful for multiple vouchers given
237 79262830 Phil Davis
	$a_vouchers_received = preg_split("/[\t\n\r ]+/s", $voucher_received);
238 05771a24 Ermal
	$error = 0;
239
	$test_result = array();     // used to display for voucher test option in GUI
240
	$total_minutes = 0;
241
	$first_voucher = "";
242
	$first_voucher_roll = 0;
243
244
	// go through all received vouchers, check their valid and extract
245
	// Roll# and Ticket# using the external readvoucher binary
246
	foreach ($a_vouchers_received as $voucher) {
247
		$v = escapeshellarg($voucher);
248 9fcbc9ff Luiz Otavio O Souza
		if (strlen($voucher) < 5) {
249 51a14c58 Phil Davis
			$voucher_err_text = sprintf(gettext("%s invalid: Too short!"), $voucher);
250
			$test_result[] = $voucher_err_text;
251
			captiveportal_syslog($voucher_err_text);
252 b08758c3 jim-p
			$error++;
253 05771a24 Ermal
			continue;   // seems too short to be a voucher!
254 79262830 Phil Davis
		}
255 05771a24 Ermal
256 b4792bf8 Ermal
		$result = exec("/usr/local/bin/voucher -c {$g['varetc_path']}/voucher_{$cpzone}.cfg -k {$g['varetc_path']}/voucher_{$cpzone}.public -- $v");
257 05771a24 Ermal
		list($status, $roll, $nr) = explode(" ", $result);
258
		if ($status == "OK") {
259
			if (!$first_voucher) {
260
				// store first voucher. Thats the one we give the timecredit
261
				$first_voucher = $voucher;
262
				$first_voucher_roll = $roll;
263
			}
264 79262830 Phil Davis
			// check if we have this ticket on a registered roll for this ticket
265 05771a24 Ermal
			if ($tickets_per_roll[$roll] && ($nr <= $tickets_per_roll[$roll])) {
266 79262830 Phil Davis
				// voucher is from a registered roll.
267
				if (!isset($active_vouchers[$roll])) {
268 05771a24 Ermal
					$active_vouchers[$roll] = voucher_read_active_db($roll);
269 79262830 Phil Davis
				}
270 05771a24 Ermal
				// valid voucher. Store roll# and ticket#
271
				if (!empty($active_vouchers[$roll][$voucher])) {
272 086cf944 Phil Davis
					list($timestamp, $minutes) = explode(",", $active_vouchers[$roll][$voucher]);
273 05771a24 Ermal
					// we have an already active voucher here.
274
					$remaining = intval((($timestamp + (60*$minutes)) - time())/60);
275 d8012adb Vinicius Coque
					$test_result[] = sprintf(gettext('%1$s (%2$s/%3$s) active and good for %4$d Minutes'), $voucher, $roll, $nr, $remaining);
276 05771a24 Ermal
					$total_minutes += $remaining;
277
				} else {
278
					// voucher not used. Check if ticket Id is on the roll (not too high)
279
					// and if the ticket is marked used.
280
					// check if voucher already marked as used
281 79262830 Phil Davis
					if (!isset($bitstring[$roll])) {
282 05771a24 Ermal
						$bitstring[$roll] = voucher_read_used_db($roll);
283 79262830 Phil Davis
					}
284 05771a24 Ermal
					$pos = $nr >> 3; // divide by 8 -> octet
285
					$mask = 1 << ($nr % 8);
286
					if (ord($bitstring[$roll][$pos]) & $mask) {
287 51a14c58 Phil Davis
						$voucher_err_text = sprintf(gettext('%1$s (%2$s/%3$s) already used and expired'), $voucher, $roll, $nr);
288
						$test_result[] = $voucher_err_text;
289
						captiveportal_syslog($voucher_err_text);
290 05771a24 Ermal
						$total_minutes = -1;    // voucher expired
291
						$error++;
292
					} else {
293
						// mark bit for this voucher as used
294
						$bitstring[$roll][$pos] = chr(ord($bitstring[$roll][$pos]) | $mask);
295 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]);
296 05771a24 Ermal
						$total_minutes += $minutes_per_roll[$roll];
297
					}
298
				}
299
			} else {
300 51a14c58 Phil Davis
				$voucher_err_text = sprintf(gettext('%1$s (%2$s/%3$s): not found on any registered Roll'), $voucher, $roll, $nr);
301
				$test_result[] = $voucher_err_text;
302
				captiveportal_syslog($voucher_err_text);
303 05771a24 Ermal
			}
304
		} else {
305
			// hmm, thats weird ... not what I expected
306 51a14c58 Phil Davis
			$voucher_err_text = sprintf(gettext('%1$s invalid: %2$s !!'), $voucher, $result);
307
			$test_result[] = $voucher_err_text;
308
			captiveportal_syslog($voucher_err_text);
309 05771a24 Ermal
			$error++;
310
		}
311
	}
312 336e3c1c Charlie
313 05771a24 Ermal
	// if this was a test call, we're done. Return the result.
314
	if ($test) {
315
		if ($error) {
316 d8012adb Vinicius Coque
			$test_result[] = gettext("Access denied!");
317 05771a24 Ermal
		} else {
318 086cf944 Phil Davis
			$test_result[] = sprintf(gettext("Access granted for %d Minutes in total."), $total_minutes);
319 05771a24 Ermal
		}
320
		unlock($voucherlck);
321 336e3c1c Charlie
322 05771a24 Ermal
		return $test_result;
323
	}
324 336e3c1c Charlie
325 05771a24 Ermal
	// if we had an error (one of the vouchers is invalid), return 0.
326
	// Discussion: we could return the time remaining for good vouchers, but then
327
	// the user wouldn't know that he used at least one invalid voucher.
328
	if ($error) {
329 830c33be Scott Ullrich
		unlock($voucherlck);
330 79262830 Phil Davis
		if ($total_minutes > 0) {   // probably not needed, but want to make sure
331 05771a24 Ermal
			$total_minutes = 0;     // we only report -1 (expired) or 0 (no access)
332 79262830 Phil Davis
		}
333 05771a24 Ermal
		return $total_minutes;       // well, at least one voucher had errors. Say NO ACCESS
334
	}
335 336e3c1c Charlie
336 05771a24 Ermal
	// All given vouchers were valid and this isn't simply a test.
337
	// Write back the used DB's
338 c14d9967 Scott Ullrich
	if (is_array($bitstring)) {
339
		foreach ($bitstring as $roll => $used) {
340 79262830 Phil Davis
			if (is_array($used)) {
341
				foreach ($used as $u) {
342 c14d9967 Scott Ullrich
					voucher_write_used_db($roll, base64_encode($u));
343 79262830 Phil Davis
				}
344 c14d9967 Scott Ullrich
			} else {
345
				voucher_write_used_db($roll, base64_encode($used));
346
			}
347
		}
348
	}
349 336e3c1c Charlie
350 05771a24 Ermal
	// Active DB: we only add the first voucher if multiple given
351
	// and give that one all the time credit. This allows the user to logout and
352
	// log in later using just the first voucher. It also keeps username limited
353
	// to one voucher and that voucher shows the correct time credit in 'active vouchers'
354
	if (!empty($active_vouchers[$first_voucher_roll][$first_voucher])) {
355
		list($timestamp, $minutes) = explode(",", $active_vouchers[$first_voucher_roll][$first_voucher]);
356
	} else {
357
		$timestamp = time();    // new voucher
358
		$minutes = $total_minutes;
359
	}
360 336e3c1c Charlie
361 05771a24 Ermal
	$active_vouchers[$first_voucher_roll][$first_voucher] = "$timestamp,$minutes";
362 80b86de5 Ermal
	voucher_write_active_db($first_voucher_roll, $active_vouchers[$first_voucher_roll]);
363 336e3c1c Charlie
364 318e3f81 Augustin-FL
	// XMLRPC Call over to the other node
365
	if (captiveportal_xmlrpc_sync_get_details($syncip, $syncport,
366
	    $syncuser, $syncpass, $carp_loop)) {
367
		$rpc_client = new pfsense_xmlrpc_client();
368
		$rpc_client->setConnectionData($syncip, $syncport, $syncuser, $syncpass);
369
		$rpc_client->set_noticefile("CaptivePortalVouchersSync");
370
		$arguments = array(
371
			'active_and_used_vouchers_bitmasks' => $bitstring,
372
			'active_vouchers' => array(
373
				$first_voucher_roll => $active_vouchers[$first_voucher_roll]
374
			)
375
		);
376
377
		$rpc_client->xmlrpc_method('captive_portal_sync',
378
			array(
379
				'op' => 'write_vouchers',
380
				'zone' => $cpzone,
381
				'arguments' => base64_encode(serialize($arguments))
382
			)
383
		);
384
	}
385
386 896889e9 Augustin-FL
	/* perform in-use vouchers expiration using check_reload_status */
387 5ebe85e9 Ermal
	send_event("service sync vouchers");
388
389 05771a24 Ermal
	unlock($voucherlck);
390 336e3c1c Charlie
391 05771a24 Ermal
	return $total_minutes;
392 336e3c1c Charlie
}
393
394 896889e9 Augustin-FL
function voucher_configure() {
395 b4792bf8 Ermal
	global $config, $g, $cpzone;
396 336e3c1c Charlie
397 b4792bf8 Ermal
	if (is_array($config['voucher'])) {
398
		foreach ($config['voucher'] as $voucherzone => $vcfg) {
399 79262830 Phil Davis
			if (platform_booting()) {
400
				echo gettext("Enabling voucher support... ");
401
			}
402 b4792bf8 Ermal
			$cpzone = $voucherzone;
403 896889e9 Augustin-FL
			$error = voucher_configure_zone();
404 285ef132 Ermal LUÇI
			if (platform_booting()) {
405 79262830 Phil Davis
				if ($error) {
406 abf421ce Ermal
					echo "error\n";
407 79262830 Phil Davis
				} else {
408 abf421ce Ermal
					echo "done\n";
409 79262830 Phil Davis
				}
410 abf421ce Ermal
			}
411 b4792bf8 Ermal
		}
412
	}
413
}
414
415 896889e9 Augustin-FL
function voucher_configure_zone() {
416 b4792bf8 Ermal
	global $config, $g, $cpzone;
417
418 79262830 Phil Davis
	if (!isset($config['voucher'][$cpzone]['enable'])) {
419 eaca40df Ermal
		return 0;
420 79262830 Phil Davis
	}
421 336e3c1c Charlie
422 b4792bf8 Ermal
	$voucherlck = lock("voucher{$cpzone}", LOCK_EX);
423 eaca40df Ermal
424 79262830 Phil Davis
	/* write public key used to verify vouchers */
425
	$pubkey = base64_decode($config['voucher'][$cpzone]['publickey']);
426
	$fd = fopen("{$g['varetc_path']}/voucher_{$cpzone}.public", "w");
427
	if (!$fd) {
428 882af7b4 jim-p
		captiveportal_syslog("Voucher error: cannot write voucher.public");
429 79262830 Phil Davis
		unlock($voucherlck);
430
		return 1;
431
	}
432
	fwrite($fd, $pubkey);
433
	fclose($fd);
434
	@chmod("{$g['varetc_path']}/voucher_{$cpzone}.public", 0600);
435
436
	/* write config file used by voucher binary to decode vouchers */
437
	$fd = fopen("{$g['varetc_path']}/voucher_{$cpzone}.cfg", "w");
438
	if (!$fd) {
439
		printf(gettext("Error: cannot write voucher.cfg") . "\n");
440
		unlock($voucherlck);
441
		return 1;
442
	}
443
	fwrite($fd, "{$config['voucher'][$cpzone]['rollbits']},{$config['voucher'][$cpzone]['ticketbits']},{$config['voucher'][$cpzone]['checksumbits']},{$config['voucher'][$cpzone]['magic']},{$config['voucher'][$cpzone]['charset']}\n");
444
	fclose($fd);
445
	@chmod("{$g['varetc_path']}/voucher_{$cpzone}.cfg", 0600);
446 c4ea3691 Ermal
	unlock($voucherlck);
447 336e3c1c Charlie
448 eaca40df Ermal
	return 0;
449 336e3c1c Charlie
}
450
451 79262830 Phil Davis
/* write bitstring of used vouchers to ramdisk.
452 336e3c1c Charlie
 * Bitstring must already be base64_encoded!
453
 */
454
function voucher_write_used_db($roll, $vdb) {
455 b4792bf8 Ermal
	global $g, $cpzone;
456 666bc4d1 Ermal
457 b4792bf8 Ermal
	$fd = fopen("{$g['vardb_path']}/voucher_{$cpzone}_used_$roll.db", "w");
458 666bc4d1 Ermal
	if ($fd) {
459
		fwrite($fd, $vdb . "\n");
460
		fclose($fd);
461 79262830 Phil Davis
	} else {
462 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));
463 79262830 Phil Davis
	}
464 336e3c1c Charlie
}
465
466
/* return assoc array of active vouchers with activation timestamp
467 79262830 Phil Davis
 * voucher is index.
468 336e3c1c Charlie
 */
469
function voucher_read_active_db($roll) {
470 b4792bf8 Ermal
	global $g, $cpzone;
471 666bc4d1 Ermal
472
	$active = array();
473
	$dirty = 0;
474 b4792bf8 Ermal
	$file = "{$g['vardb_path']}/voucher_{$cpzone}_active_$roll.db";
475 666bc4d1 Ermal
	if (file_exists($file)) {
476
		$fd = fopen($file, "r");
477
		if ($fd) {
478
			while (!feof($fd)) {
479
				$line = trim(fgets($fd));
480
				if ($line) {
481 086cf944 Phil Davis
					list($voucher, $timestamp, $minutes) = explode(",", $line); // voucher,timestamp
482 79262830 Phil Davis
					if ((($timestamp + (60*$minutes)) - time()) > 0) {
483 666bc4d1 Ermal
						$active[$voucher] = "$timestamp,$minutes";
484 79262830 Phil Davis
					} else {
485 666bc4d1 Ermal
						$dirty=1;
486 79262830 Phil Davis
					}
487 666bc4d1 Ermal
				}
488
			}
489
			fclose($fd);
490 896889e9 Augustin-FL
			if ($dirty) { // if we found expired entries, lets remove them
491 666bc4d1 Ermal
				voucher_write_active_db($roll, $active);
492 5ebe85e9 Ermal
			}
493 666bc4d1 Ermal
		}
494
	}
495
	return $active;
496 336e3c1c Charlie
}
497
498
/* store array of active vouchers back to DB */
499
function voucher_write_active_db($roll, $active) {
500 79262830 Phil Davis
	global $g, $cpzone;
501 336e3c1c Charlie
502 79262830 Phil Davis
	if (!is_array($active)) {
503 05771a24 Ermal
		return;
504 79262830 Phil Davis
	}
505
	$fd = fopen("{$g['vardb_path']}/voucher_{$cpzone}_active_$roll.db", "w");
506
	if ($fd) {
507
		foreach ($active as $voucher => $value) {
508
			fwrite($fd, "$voucher,$value\n");
509
		}
510
		fclose($fd);
511
	}
512 336e3c1c Charlie
}
513
514
/* return how many vouchers are marked used on a roll */
515
function voucher_used_count($roll) {
516 79262830 Phil Davis
	global $g, $cpzone;
517
518
	$bitstring = voucher_read_used_db($roll);
519
	$max = strlen($bitstring) * 8;
520
	$used = 0;
521
	for ($i = 1; $i <= $max; $i++) {
522
		// check if ticket already used or not.
523
		$pos = $i >> 3;            // divide by 8 -> octet
524
		$mask = 1 << ($i % 8);  // mask to test bit in octet
525
		if (ord($bitstring[$pos]) & $mask) {
526
			$used++;
527
		}
528
	}
529
	unset($bitstring);
530
531
	return $used;
532 336e3c1c Charlie
}
533
534
function voucher_read_used_db($roll) {
535 79262830 Phil Davis
	global $g, $cpzone;
536
537
	$vdb = "";
538
	$file = "{$g['vardb_path']}/voucher_{$cpzone}_used_$roll.db";
539
	if (file_exists($file)) {
540
		$fd = fopen($file, "r");
541
		if ($fd) {
542
			$vdb = trim(fgets($fd));
543
			fclose($fd);
544
		} else {
545 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));
546 79262830 Phil Davis
		}
547
	}
548
	return base64_decode($vdb);
549 336e3c1c Charlie
}
550
551
function voucher_unlink_db($roll) {
552 79262830 Phil Davis
	global $g, $cpzone;
553
	@unlink("{$g['vardb_path']}/voucher_{$cpzone}_used_$roll.db");
554
	@unlink("{$g['vardb_path']}/voucher_{$cpzone}_active_$roll.db");
555 336e3c1c Charlie
}
556
557
/* we share the log with captiveportal for now */
558
function voucher_log($priority, $message) {
559
560 79262830 Phil Davis
	$message = trim($message);
561
	openlog("logportalauth", LOG_PID, LOG_LOCAL4);
562 086cf944 Phil Davis
	syslog($priority, sprintf(gettext("Voucher: %s"), $message));
563 79262830 Phil Davis
	closelog();
564 336e3c1c Charlie
}
565
566 896889e9 Augustin-FL
/* Perform natural expiration of vouchers
567 5ebe85e9 Ermal
 * Called during reboot -> system_reboot_cleanup() and every active voucher change
568 336e3c1c Charlie
 */
569
function voucher_save_db_to_config() {
570 896889e9 Augustin-FL
	global $config, $g;
571 b4792bf8 Ermal
572
	if (is_array($config['voucher'])) {
573 896889e9 Augustin-FL
		foreach ($config['voucher'] as $zone => $vcfg) {
574
			if (isset($config['voucher'][$zone]['enable']) && is_array($config['voucher'][$zone]['roll'])) {
575
				foreach ($config['voucher'][$zone]['roll'] as $key => $rollent) {
576
					// read_active_db will remove expired vouchers that are still active
577
					voucher_read_active_db($rollent['number']);
578
				}
579
			}
580 79262830 Phil Davis
		}
581
	}
582 336e3c1c Charlie
}
583
584 2ee5fe9b Ermal Lu?i
?>