Project

General

Profile

Download (15.3 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * notices.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2005 Colin Smith (ethethlay@gmail.com)
7
 * Copyright (c) 2005-2013 BSD Perimeter
8
 * Copyright (c) 2013-2016 Electric Sheep Fencing
9
 * Copyright (c) 2014-2020 Rubicon Communications, LLC (Netgate)
10
 * All rights reserved.
11
 *
12
 * Licensed under the Apache License, Version 2.0 (the "License");
13
 * you may not use this file except in compliance with the License.
14
 * You may obtain a copy of the License at
15
 *
16
 * http://www.apache.org/licenses/LICENSE-2.0
17
 *
18
 * Unless required by applicable law or agreed to in writing, software
19
 * distributed under the License is distributed on an "AS IS" BASIS,
20
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
 * See the License for the specific language governing permissions and
22
 * limitations under the License.
23
 */
24

    
25
require_once("globals.inc");
26
require_once("functions.inc");
27
require_once("led.inc");
28

    
29
$notice_path = $g['tmp_path'] . '/notices';
30
global $smtp_authentication_mechanisms;
31
$smtp_authentication_mechanisms = array(
32
	'PLAIN' => 'PLAIN',
33
	'LOGIN' => 'LOGIN');
34
/* Other SMTP Authentication Mechanisms that could be supported.
35
 * Note that MD5 is no longer considered secure.
36
 *	'GSSAPI' => 'GSSAPI ' . gettext("Generic Security Services Application Program Interface")
37
 *	'DIGEST-MD5' => 'DIGEST-MD5 ' . gettext("Digest access authentication")
38
 *	'MD5' => 'MD5'
39
 *	'CRAM-MD5' => 'CRAM-MD5'
40
*/
41
global $pushover_sounds;
42
$pushover_sounds = array(
43
	'devicedefault' => 'Device Default',
44
	'pushover' => 'Pushover',
45
	'bike' => 'Bike',
46
	'bugle' => 'Bugle',
47
	'cashregister' => 'Cash Register',
48
	'classical' => 'Classical',
49
	'cosmic' => 'Cosmic',
50
	'falling' => 'Falling',
51
	'gamelan' => 'Gamelan',
52
	'incoming' => 'Incomming',
53
	'intermission' => 'Intermission',
54
	'magic' => 'Magic',
55
	'mechanical' => 'Mechanical',
56
	'pianobar' => 'Piano Bar',
57
	'siren' => 'Siren',
58
	'spacealarm' => 'Space Alarm',
59
	'tugboat' => 'Tug Boat',
60
	'alien' => 'Alien (long)',
61
	'climb' => 'Climb (long)',
62
	'persistent' => 'Persistent (long)',
63
	'echo' => 'Echo (long)',
64
	'updown' => 'Up Down (long)',
65
	'vibrate' => 'Vibrate only',
66
	'none' => 'None (silent)');
67

    
68
/****f* notices/file_notice
69
 * NAME
70
 *   file_notice
71
 * INPUTS
72
 *	 $id, $notice, $category, $url, $priority, $local_only
73
 * RESULT
74
 *   Files a notice and kicks off the various alerts, smtp, telegram, pushover, system log, LED's, etc.
75
 *   If $local_only is true then the notice is not sent to external places (smtp, telegram, pushover)
76
 ******/
77
function file_notice($id, $notice, $category = "General", $url = "", $priority = 1, $local_only = false) {
78
	/*
79
	 * $category - Category that this notice should be displayed under. This can be arbitrary,
80
	 * 	       but a page must be set to receive this messages for it to be displayed.
81
	 *
82
	 * $priority - A notice's priority. Higher numbers indicate greater severity.
83
	 *	       0 = informational, 1 = warning, 2 = error, etc. This may also be arbitrary,
84
	 */
85
	global $notice_path;
86
	if (!$queue = get_notices()) {
87
		$queue = array();
88
	}
89
	$queuekey = time();
90
	$toqueue = array(
91
				'id'		=> htmlentities($id),
92
				'notice'	=> htmlentities($notice),
93
				'url'		=> htmlentities($url),
94
				'category'	=> htmlentities($category),
95
				'priority'	=> htmlentities($priority),
96
			);
97
	while (isset($queue[$queuekey])) {
98
		$queuekey++;
99
	}
100
	$queue[$queuekey] = $toqueue;
101
	$queueout = fopen($notice_path, "w");
102
	if (!$queueout) {
103
		log_error(sprintf(gettext("Could not open %s for writing"), $notice_path));
104
		return;
105
	}
106
	fwrite($queueout, serialize($queue));
107
	fclose($queueout);
108
	openlog("", LOG_PID, LOG_LOCAL0);
109
	log_error(sprintf(gettext("New alert found: %s"), $notice));
110
	/* soekris */
111
	if (file_exists("/dev/led/error")) {
112
		exec("/bin/echo 1 > /dev/led/error");
113
	}
114
	/* wrap & alix */
115
	led_normalize();
116
	led_morse(1, 'sos');
117
	if (!$local_only) {
118
		notify_all_remote($notice);
119
	}
120
	return $queuekey;
121
}
122

    
123
/****f* notices/get_notices
124
 * NAME
125
 *   get_notices
126
 * INPUTS
127
 *	 $category
128
 * RESULT
129
 *   Returns a specific notices text
130
 ******/
131
function get_notices($category = "all") {
132
	global $g;
133

    
134
	if (file_exists("{$g['tmp_path']}/notices")) {
135
		$queue = unserialize(file_get_contents("{$g['tmp_path']}/notices"));
136
		if (!$queue) {
137
			return false;
138
		}
139
		if ($category != 'all') {
140
			foreach ($queue as $time => $notice) {
141
				if (strtolower($notice['category']) == strtolower($category)) {
142
					$toreturn[$time] = $notice;
143
				}
144
			}
145
			return $toreturn;
146
		} else {
147
			return $queue;
148
		}
149
	} else {
150
		return false;
151
	}
152
}
153

    
154
/****f* notices/close_notice
155
 * NAME
156
 *   close_notice
157
 * INPUTS
158
 *	 $id
159
 * RESULT
160
 *   Removes a notice from the list
161
 ******/
162
function close_notice($id) {
163
	global $notice_path;
164
	require_once("util.inc");
165
	/* soekris */
166
	if (file_exists("/dev/led/error")) {
167
		exec("/bin/echo 0 > /dev/led/error");
168
	}
169
	/* wrap & alix */
170
	led_normalize();
171
	$ids = array();
172
	if (!$notices = get_notices()) {
173
		return;
174
	}
175
	if ($id == "all") {
176
		unlink_if_exists($notice_path);
177
		return;
178
	}
179
	foreach (array_keys($notices) as $time) {
180
		if ($id == $time) {
181
			unset($notices[$id]);
182
			break;
183
		}
184
	}
185
	foreach ($notices as $key => $notice) {
186
		$ids[$key] = $notice['id'];
187
	}
188
	foreach ($ids as $time => $tocheck) {
189
		if ($id == $tocheck) {
190
			unset($notices[$time]);
191
			break;
192
		}
193
	}
194
	if (count($notices) != 0) {
195
		$queueout = fopen($notice_path, "w");
196
		fwrite($queueout, serialize($notices));
197
		fclose($queueout);
198
	} else {
199
		unlink_if_exists($notice_path);
200
	}
201

    
202
	return;
203
}
204

    
205
/****f* notices/dump_xml_notices
206
 * NAME
207
 *   dump_xml_notices
208
 * INPUTS
209
 *	 NONE
210
 * RESULT
211
 *   Outputs notices in XML formatted text
212
 ******/
213
function dump_xml_notices() {
214
	if (file_exists("/cf/conf/use_xmlreader")) {
215
		require_once("xmlreader.inc");
216
	} else {
217
		require_once("xmlparse.inc");
218
	}
219
	global $notice_path, $listtags;
220
	$listtags[] = 'notice';
221
	if (!$notices = get_notices()) {
222
		return;
223
	}
224
	foreach ($notices as $time => $notice) {
225
		$notice['time'] = $time;
226
		$toput['notice'][] = $notice;
227
	}
228
	$xml = dump_xml_config($toput, 'notices');
229
	return $xml;
230
}
231

    
232
/****f* notices/are_notices_pending
233
 * NAME
234
 *   are_notices_pending
235
 * INPUTS
236
 *	 $category to check
237
 * RESULT
238
 *   returns true if notices are pending, false if they are not
239
 ******/
240
function are_notices_pending($category = "all") {
241
	global $notice_path;
242
	if (file_exists($notice_path)) {
243
		return true;
244
	}
245
	return false;
246
}
247

    
248
function notices_sendqueue() {
249
	global $g;
250
	$nothing_done_count = 0;
251
	$messagequeue = array();
252

    
253
	while(true) {
254
		$notifyqueue_lck = lock("notifyqueue", LOCK_EX);
255
		$nothing_done_count++;
256
		$smptcount = 0;
257
		$messages = array();
258
		if (file_exists("{$g['vardb_path']}/notifyqueue.messages")) {
259
			$messages = unserialize(file_get_contents("{$g['vardb_path']}/notifyqueue.messages"));
260
			$messagequeue = $messages;
261
			$messages['mails']['item'] = array(); // clear all items to be send
262
			file_put_contents("{$g['vardb_path']}/notifyqueue.messages", serialize($messages));
263
			unset($messages);
264
		}
265
		// clear lock before trying to send messages, so new one's can be added
266
		unlock($notifyqueue_lck);
267

    
268
		if (is_array($messagequeue['mails']['item'])) {
269
			$smtpmessage = "";
270
			foreach($messagequeue['mails']['item'] as $mail) {
271
				switch ($mail['type']) {
272
					case 'mail':
273
						$smptcount++;
274
						$smtpmessage .= "\r\n" . date("G:i:s",$mail['time']) . " " . $mail['msg'];
275
						break;
276
					default:
277
						break;
278
				}
279
			}
280
			if (!empty($smtpmessage)) {
281
				$smtpmessageheader = sprintf(gettext("Notifications in this message: %s"), $smptcount);
282
				$smtpmessageheader .= "\n" . str_repeat('=', strlen($smtpmessageheader)) . "\n";
283
				$nothing_done_count = 0;
284
				notify_via_smtp($smtpmessageheader . $smtpmessage, true);
285
			}
286
		}
287
		if ($nothing_done_count > 6) {
288
			break;
289
		} else {
290
			sleep(10);
291
		}
292
	}
293
}
294

    
295
function notify_via_queue_add($message, $type='mail') {
296
	global $g;
297
	$mail = array();
298
	$mail['time'] = time();
299
	$mail['type'] = $type;
300
	$mail['msg'] = $message;
301
	$notifyqueue_lck = lock("notifyqueue", LOCK_EX);
302
	$messages = array();
303
	if (file_exists("{$g['vardb_path']}/notifyqueue.messages")) {
304
		$messages = unserialize(file_get_contents("{$g['vardb_path']}/notifyqueue.messages"));
305
	}
306
	if(is_array($messages)) {
307
		$messages['mails']['item'][] = $mail;
308
		file_put_contents("{$g['vardb_path']}/notifyqueue.messages", serialize($messages));
309
	}
310
	unset($messages);
311

    
312
	mwexec_bg('/usr/local/bin/notify_monitor.php');
313
	unlock($notifyqueue_lck);
314
}
315

    
316
/****f* notices/notify_via_smtp
317
 * NAME
318
 *   notify_via_smtp
319
 * INPUTS
320
 *	 notification string to send as an email
321
 * RESULT
322
 *   returns true if message was sent
323
 ******/
324
function notify_via_smtp($message, $force = false) {
325
	global $config, $g;
326
	if (platform_booting()) {
327
		return;
328
	}
329

    
330
	if (isset($config['notifications']['smtp']['disable']) && !$force) {
331
		return;
332
	}
333

    
334
	/* Do NOT send the same message twice, except if $force is true */
335
	if (!$force && file_exists("/var/db/notices_lastmsg.txt")) {
336
		$lastmsg = trim(file_get_contents("/var/db/notices_lastmsg.txt"));
337
		if ($lastmsg == $message) {
338
			return;
339
		}
340
	}
341

    
342
	/* Store last message sent to avoid spamming */
343
	@file_put_contents("/var/db/notices_lastmsg.txt", $message);
344
	if (!$force) {
345
		notify_via_queue_add($message, 'mail');
346
		$ret = true;
347
	} else {
348
		$ret = send_smtp_message($message, "{$config['system']['hostname']}.{$config['system']['domain']} - Notification", $force);
349
	}
350

    
351
	return $ret;
352
}
353

    
354
function send_smtp_message($message, $subject = "(no subject)", $force = false) {
355
	global $config, $g;
356
	require_once("Mail.php");
357

    
358
	if (isset($config['notifications']['smtp']['disable']) && !$force) {
359
		return;
360
	}
361

    
362
	if (!$config['notifications']['smtp']['ipaddress']) {
363
		return;
364
	}
365

    
366
	if (!$config['notifications']['smtp']['notifyemailaddress']) {
367
		return;
368
	}
369

    
370
	$to = $config['notifications']['smtp']['notifyemailaddress'];
371

    
372
	if (empty($config['notifications']['smtp']['username']) ||
373
	    empty($config['notifications']['smtp']['password'])) {
374
		$auth = false;
375
		$username = '';
376
		$password = '';
377
	} else {
378
		$auth = isset($config['notifications']['smtp']['authentication_mechanism'])
379
		    ? $config['notifications']['smtp']['authentication_mechanism']
380
		    : 'PLAIN';
381
		$username = $config['notifications']['smtp']['username'];
382
		$password = $config['notifications']['smtp']['password'];
383
	}
384

    
385
	$params = array(
386
		'host' => (isset($config['notifications']['smtp']['ssl'])
387
		    ? 'ssl://'
388
		    : '')
389
		    . $config['notifications']['smtp']['ipaddress'],
390
		'port' => empty($config['notifications']['smtp']['port'])
391
		    ? 25
392
		    : $config['notifications']['smtp']['port'],
393
		'auth' => $auth,
394
		'username' => $username,
395
		'password' => $password,
396
		'localhost' => $config['system']['hostname'] . "." .
397
		    $config['system']['domain'],
398
		'timeout' => !empty($config['notifications']['smtp']['timeout'])
399
		    ? $config['notifications']['smtp']['timeout']
400
		    : 20,
401
		'debug' => false,
402
		'persist' => false
403
	);
404

    
405
	if ($config['notifications']['smtp']['sslvalidate'] == "disabled") {
406
		$params['socket_options'] = array(
407
			'ssl' => array(
408
				'verify_peer_name' => false,
409
				'verify_peer' => false
410
		));
411
	}
412

    
413
	if ($config['notifications']['smtp']['fromaddress']) {
414
		$from = $config['notifications']['smtp']['fromaddress'];
415
	} else {
416
		$from = "pfsense@{$config['system']['hostname']}.{$config['system']['domain']}";
417
	}
418

    
419
	$headers = array(
420
		"From"    => $from,
421
		"To"      => $to,
422
		"Subject" => $subject,
423
		"Date"    => date("r")
424
	);
425

    
426
	$smtp =& Mail::factory('smtp', $params);
427
	$mail = $smtp->send($to, $headers, $message);
428

    
429
	if (PEAR::isError($mail)) {
430
		$err_msg = sprintf(gettext(
431
		    'Could not send the message to %1$s -- Error: %2$s'),
432
		    $to, $mail->getMessage());
433
		log_error($err_msg);
434
		return($err_msg);
435
	}
436

    
437
	log_error(sprintf(gettext("Message sent to %s OK"), $to));
438
	return;
439
}
440
/****f* notices/notify_via_telegram
441
 * NAME
442
 *   notify_via_telegram
443
 * INPUTS
444
 *	 notification string to send to Telegram via API
445
 * RESULT
446
 *   returns NULL if message was sent
447
 ******/
448

    
449
function notify_via_telegram($message, $force = false) {
450
	global $config;
451
	if ((!isset($config['notifications']['telegram']['enabled']) && (!$force))
452
	    || !$config['notifications']['telegram']['api']
453
	    || !$config['notifications']['telegram']['chatid']) {
454
		if ($force) {
455
			return gettext("Unable to test Telegram notification without both API Key & Chat ID set");
456
		}
457
		return;
458
	}
459

    
460
	$url = "https://api.telegram.org/bot{$config['notifications']['telegram']['api']}/sendMessage?";
461
	$data = array(
462
		"chat_id" => $config['notifications']['telegram']['chatid'],
463
		"text" => "{$config['system']['hostname']}.{$config['system']['domain']}\n{$message}"
464
	);
465
	$result = json_decode(curl_post_telegram($url . http_build_query($data)), true);
466
	if (is_array($result)) {
467
		if ($result['ok']) {
468
			unset($err_msg);
469
		} else {
470
			$err_msg = sprintf(gettext("Failed to send Telegram notification. Error received was :{$result['error_code']}: {$result['description']}"));
471
			log_error($err_msg);
472
		}
473
	} else {
474
		$err_msg = gettext("API to Telegram did not return data in expected format!");
475
		log_error($err_msg);
476
	}
477
	return $err_msg;
478
}
479

    
480
function curl_post_telegram($url) {
481
	$conn = curl_init($url);
482
	curl_setopt($conn, CURLOPT_SSL_VERIFYPEER, true);
483
	curl_setopt($conn, CURLOPT_FRESH_CONNECT,  true);
484
	curl_setopt($conn, CURLOPT_RETURNTRANSFER, 1);
485
	$curl_post_telegram_data = curl_exec($conn);
486
	curl_close($conn);
487
	return $curl_post_telegram_data;	//json encoded
488
}
489

    
490
/****f* notices/notify_via_pushover
491
 * NAME
492
 *   notify_via_pushover
493
 * INPUTS
494
 *	 notification string to send to Pushover via API
495
 * RESULT
496
 *   returns NULL if message was sent
497
 ******/
498

    
499
function notify_via_pushover($message, $force = false) {
500
	global $config;
501
	if ((!isset($config['notifications']['pushover']['enabled']) && (!$force))
502
	    || !$config['notifications']['pushover']['apikey']
503
	    || !$config['notifications']['pushover']['userkey']) {
504
		if ($force) {
505
			return gettext("Unable to test Pushover notification without both API Key & User Key set");
506
		}
507
		return;
508
	}
509
	if (strcasecmp($config['notifications']['pushover']['sound'], 'devicedefault') == 0) {
510
		unset($config['notifications']['pushover']['sound']);
511
	}
512

    
513
	$url = "https://api.pushover.net/1/messages.json";
514
	$data = array(
515
		"token" => $config['notifications']['pushover']['apikey'],
516
		"user" => $config['notifications']['pushover']['userkey'],
517
		"sound" => $config['notifications']['pushover']['sound'],
518
		"priority" => $config['notifications']['pushover']['priority'],
519
		"retry" => $config['notifications']['pushover']['retry'],
520
		"expire" => $config['notifications']['pushover']['expire'],
521
		"message" => "{$config['system']['hostname']}.{$config['system']['domain']}\n{$message}"
522
	);
523
	$result = json_decode(curl_post_pushover($url, $data), true);
524
	if (is_array($result)) {
525
		if ($result['status']) {
526
			unset($err_msg);
527
		} else {
528
			$err_msg = sprintf(gettext("Failed to send Pushover notification. Error received was: %s"), $result['errors']['0']);
529
			log_error($err_msg);
530
		}
531
	} else {
532
		$err_msg = gettext("Pushover API server did not return data in expected format!");
533
		log_error($err_msg);
534
	}
535
	return $err_msg;
536
}
537

    
538
function curl_post_pushover($url, $data) {
539
	$conn = curl_init($url);
540
	curl_setopt($conn, CURLOPT_POSTFIELDS, $data);
541
	curl_setopt($conn, CURLOPT_SSL_VERIFYPEER, true);
542
	curl_setopt($conn, CURLOPT_FRESH_CONNECT,  true);
543
	curl_setopt($conn, CURLOPT_RETURNTRANSFER, 1);
544
	$curl_post_pushover_data = curl_exec($conn);
545
	curl_close($conn);
546
	return $curl_post_pushover_data;	//json encoded
547
}
548

    
549
/* Notify via remote methods only - not via GUI. */
550
function notify_all_remote($msg) {
551
	notify_via_smtp($msg);
552
	notify_via_telegram($msg);
553
	notify_via_pushover($msg);
554
}
555

    
556
?>
(30-30/61)