Project

General

Profile

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