Project

General

Profile

Download (14.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-2018 Rubicon Communications, LLC (Netgate)
8
 * All rights reserved.
9
 *
10
 * Licensed under the Apache License, Version 2.0 (the "License");
11
 * you may not use this file except in compliance with the License.
12
 * You may obtain a copy of the License at
13
 *
14
 * http://www.apache.org/licenses/LICENSE-2.0
15
 *
16
 * Unless required by applicable law or agreed to in writing, software
17
 * distributed under the License is distributed on an "AS IS" BASIS,
18
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
 * See the License for the specific language governing permissions and
20
 * limitations under the License.
21
 */
22

    
23
require_once("globals.inc");
24
require_once("functions.inc");
25
require_once("led.inc");
26

    
27
$notice_path = $g['tmp_path'] . '/notices';
28
$smtp_authentication_mechanisms = array(
29
	'PLAIN' => 'PLAIN',
30
	'LOGIN' => 'LOGIN');
31
/* Other SMTP Authentication Mechanisms that could be supported.
32
 * Note that MD5 is no longer considered secure.
33
 *	'GSSAPI' => 'GSSAPI ' . gettext("Generic Security Services Application Program Interface")
34
 *	'DIGEST-MD5' => 'DIGEST-MD5 ' . gettext("Digest access authentication")
35
 *	'MD5' => 'MD5'
36
 *	'CRAM-MD5' => 'CRAM-MD5'
37
*/
38

    
39
/****f* notices/file_notice
40
 * NAME
41
 *   file_notice
42
 * INPUTS
43
 *	 $id, $notice, $category, $url, $priority, $local_only
44
 * RESULT
45
 *   Files a notice and kicks off the various alerts, smtp, growl, system log, LED's, etc.
46
 *   If $local_only is true then the notice is not sent to external places (smtp, growl)
47
 ******/
48
function file_notice($id, $notice, $category = "General", $url = "", $priority = 1, $local_only = false) {
49
	/*
50
	 * $category - Category that this notice should be displayed under. This can be arbitrary,
51
	 * 	       but a page must be set to receive this messages for it to be displayed.
52
	 *
53
	 * $priority - A notice's priority. Higher numbers indicate greater severity.
54
	 *	       0 = informational, 1 = warning, 2 = error, etc. This may also be arbitrary,
55
	 */
56
	global $notice_path;
57
	if (!$queue = get_notices()) {
58
		$queue = array();
59
	}
60
	$queuekey = time();
61
	$toqueue = array(
62
				'id'		=> htmlentities($id),
63
				'notice'	=> htmlentities($notice),
64
				'url'		=> htmlentities($url),
65
				'category'	=> htmlentities($category),
66
				'priority'	=> htmlentities($priority),
67
			);
68
	while (isset($queue[$queuekey])) {
69
		$queuekey++;
70
	}
71
	$queue[$queuekey] = $toqueue;
72
	$queueout = fopen($notice_path, "w");
73
	if (!$queueout) {
74
		log_error(sprintf(gettext("Could not open %s for writing"), $notice_path));
75
		return;
76
	}
77
	fwrite($queueout, serialize($queue));
78
	fclose($queueout);
79
	log_error(sprintf(gettext("New alert found: %s"), $notice));
80
	/* soekris */
81
	if (file_exists("/dev/led/error")) {
82
		exec("/bin/echo 1 > /dev/led/error");
83
	}
84
	/* wrap & alix */
85
	led_normalize();
86
	led_morse(1, 'sos');
87
	if (!$local_only) {
88
		notify_all_remote($notice);
89
	}
90
	return $queuekey;
91
}
92

    
93
/****f* notices/get_notices
94
 * NAME
95
 *   get_notices
96
 * INPUTS
97
 *	 $category
98
 * RESULT
99
 *   Returns a specific notices text
100
 ******/
101
function get_notices($category = "all") {
102
	global $g;
103

    
104
	if (file_exists("{$g['tmp_path']}/notices")) {
105
		$queue = unserialize(file_get_contents("{$g['tmp_path']}/notices"));
106
		if (!$queue) {
107
			return false;
108
		}
109
		if ($category != 'all') {
110
			foreach ($queue as $time => $notice) {
111
				if (strtolower($notice['category']) == strtolower($category)) {
112
					$toreturn[$time] = $notice;
113
				}
114
			}
115
			return $toreturn;
116
		} else {
117
			return $queue;
118
		}
119
	} else {
120
		return false;
121
	}
122
}
123

    
124
/****f* notices/close_notice
125
 * NAME
126
 *   close_notice
127
 * INPUTS
128
 *	 $id
129
 * RESULT
130
 *   Removes a notice from the list
131
 ******/
132
function close_notice($id) {
133
	global $notice_path;
134
	require_once("util.inc");
135
	/* soekris */
136
	if (file_exists("/dev/led/error")) {
137
		exec("/bin/echo 0 > /dev/led/error");
138
	}
139
	/* wrap & alix */
140
	led_normalize();
141
	$ids = array();
142
	if (!$notices = get_notices()) {
143
		return;
144
	}
145
	if ($id == "all") {
146
		unlink_if_exists($notice_path);
147
		return;
148
	}
149
	foreach (array_keys($notices) as $time) {
150
		if ($id == $time) {
151
			unset($notices[$id]);
152
			break;
153
		}
154
	}
155
	foreach ($notices as $key => $notice) {
156
		$ids[$key] = $notice['id'];
157
	}
158
	foreach ($ids as $time => $tocheck) {
159
		if ($id == $tocheck) {
160
			unset($notices[$time]);
161
			break;
162
		}
163
	}
164
	if (count($notices) != 0) {
165
		$queueout = fopen($notice_path, "w");
166
		fwrite($queueout, serialize($notices));
167
		fclose($queueout);
168
	} else {
169
		unlink_if_exists($notice_path);
170
	}
171

    
172
	return;
173
}
174

    
175
/****f* notices/dump_xml_notices
176
 * NAME
177
 *   dump_xml_notices
178
 * INPUTS
179
 *	 NONE
180
 * RESULT
181
 *   Outputs notices in XML formatted text
182
 ******/
183
function dump_xml_notices() {
184
	if (file_exists("/cf/conf/use_xmlreader")) {
185
		require_once("xmlreader.inc");
186
	} else {
187
		require_once("xmlparse.inc");
188
	}
189
	global $notice_path, $listtags;
190
	$listtags[] = 'notice';
191
	if (!$notices = get_notices()) {
192
		return;
193
	}
194
	foreach ($notices as $time => $notice) {
195
		$notice['time'] = $time;
196
		$toput['notice'][] = $notice;
197
	}
198
	$xml = dump_xml_config($toput, 'notices');
199
	return $xml;
200
}
201

    
202
/****f* notices/are_notices_pending
203
 * NAME
204
 *   are_notices_pending
205
 * INPUTS
206
 *	 $category to check
207
 * RESULT
208
 *   returns true if notices are pending, false if they are not
209
 ******/
210
function are_notices_pending($category = "all") {
211
	global $notice_path;
212
	if (file_exists($notice_path)) {
213
		return true;
214
	}
215
	return false;
216
}
217

    
218
function notices_sendqueue() {
219
	global $g;
220
	$nothing_done_count = 0;
221
	$messagequeue = array();
222
	$growlerrorcount = 0;
223
	$growlskipped = 0;
224

    
225
	while(true) {
226
		$notifyqueue_lck = lock("notifyqueue", LOCK_EX);
227
		$nothing_done_count++;
228
		$smptcount = 0;
229
		$messages = array();
230
		if (file_exists("{$g['vardb_path']}/notifyqueue.messages")) {
231
			$messages = unserialize(file_get_contents("{$g['vardb_path']}/notifyqueue.messages"));
232
			$messagequeue = $messages;
233
			$messages['mails']['item'] = array(); // clear all items to be send
234
			file_put_contents("{$g['vardb_path']}/notifyqueue.messages", serialize($messages));
235
			unset($messages);
236
		}
237
		// clear lock before trying to send messages, so new one's can be added
238
		unlock($notifyqueue_lck);
239

    
240
		if (is_array($messagequeue['mails']['item'])) {
241
			$smtpmessage = "";
242
			$growlqueue = array();
243
			foreach($messagequeue['mails']['item'] as $mail) {
244
				switch ($mail['type']) {
245
					case 'mail':
246
						$smptcount++;
247
						$smtpmessage .= "\r\n" . date("G:i:s",$mail['time']) . " " . $mail['msg'];
248
						break;
249
					case 'growl':
250
						$message = date("G:i:s",$mail['time']) . " " . $mail['msg'];
251
						$nothing_done_count = 0;
252
						$growlqueue[] = $message;
253
						break;
254
					default:
255
						break;
256
				}
257
			}
258
			if (!empty($smtpmessage)) {
259
				$smtpmessageheader = sprintf(gettext("Notifications in this message: %s"), $smptcount);
260
				$smtpmessageheader .= "\n" . str_repeat('=', strlen($smtpmessageheader)) . "\n";
261
				$nothing_done_count = 0;
262
				notify_via_smtp($smtpmessageheader . $smtpmessage, true);
263
			}
264
			if (count($growlqueue) > 0) {
265
				$nothing_done_count = 0;
266
				foreach($growlqueue as $message) {
267
					if ($growlerrorcount < 3) {
268
						$ret = notify_via_growl($message, true);
269
						if (!empty($ret)) {
270
							$growlerrorcount++;
271
						}
272
					} else {
273
						$growlskipped++;
274
					}
275
				}
276
			}
277
		}
278
		if ($nothing_done_count > 6) {
279
			break;
280
		} else {
281
			sleep(10);
282
		}
283
	}
284
	if ($growlskipped > 0) {
285
		log_error("{$growlskipped} growl notifications were skipped due to to many errors: {$growlerrorcount}.");
286
	}
287
}
288

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

    
306
	mwexec_bg('/usr/local/bin/notify_monitor.php');
307
	unlock($notifyqueue_lck);
308
}
309

    
310
/****f* notices/notify_via_smtp
311
 * NAME
312
 *   notify_via_smtp
313
 * INPUTS
314
 *	 notification string to send as an email
315
 * RESULT
316
 *   returns true if message was sent
317
 ******/
318
function notify_via_smtp($message, $force = false) {
319
	global $config, $g;
320
	if (platform_booting()) {
321
		return;
322
	}
323

    
324
	if (isset($config['notifications']['smtp']['disable']) && !$force) {
325
		return;
326
	}
327

    
328
	/* Do NOT send the same message twice, except if $force is true */
329
	if (!$force && file_exists("/var/db/notices_lastmsg.txt")) {
330
		$lastmsg = trim(file_get_contents("/var/db/notices_lastmsg.txt"));
331
		if ($lastmsg == $message) {
332
			return;
333
		}
334
	}
335

    
336
	/* Store last message sent to avoid spamming */
337
	@file_put_contents("/var/db/notices_lastmsg.txt", $message);
338
	if (!$force) {
339
		notify_via_queue_add($message, 'mail');
340
		$ret = true;
341
	} else {
342
		$ret = send_smtp_message($message, "{$config['system']['hostname']}.{$config['system']['domain']} - Notification", $force);
343
	}
344

    
345
	return $ret;
346
}
347

    
348
function send_smtp_message($message, $subject = "(no subject)", $force = false) {
349
	global $config, $g;
350
	require_once("Mail.php");
351

    
352
	if (isset($config['notifications']['smtp']['disable']) && !$force) {
353
		return;
354
	}
355

    
356
	if (!$config['notifications']['smtp']['ipaddress']) {
357
		return;
358
	}
359

    
360
	if (!$config['notifications']['smtp']['notifyemailaddress']) {
361
		return;
362
	}
363

    
364
	$to = $config['notifications']['smtp']['notifyemailaddress'];
365

    
366
	if (empty($config['notifications']['smtp']['username']) ||
367
	    empty($config['notifications']['smtp']['password'])) {
368
		$auth = false;
369
		$username = '';
370
		$password = '';
371
	} else {
372
		$auth = isset($config['notifications']['smtp']['authentication_mechanism'])
373
		    ? $config['notifications']['smtp']['authentication_mechanism']
374
		    : 'PLAIN';
375
		$username = $config['notifications']['smtp']['username'];
376
		$password = $config['notifications']['smtp']['password'];
377
	}
378

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

    
399
	if ($config['notifications']['smtp']['fromaddress']) {
400
		$from = $config['notifications']['smtp']['fromaddress'];
401
	} else {
402
		$from = "pfsense@{$config['system']['hostname']}.{$config['system']['domain']}";
403
	}
404

    
405
	$headers = array(
406
		"From"    => $from,
407
		"To"      => $to,
408
		"Subject" => $subject,
409
		"Date"    => date("r")
410
	);
411

    
412
	$smtp =& Mail::factory('smtp', $params);
413
	$mail = $smtp->send($to, $headers, $message);
414

    
415
	if (PEAR::isError($mail)) {
416
		$err_msg = sprintf(gettext(
417
		    'Could not send the message to %1$s -- Error: %2$s'),
418
		    $to, $mail->getMessage());
419
		log_error($err_msg);
420
		return($err_msg);
421
	}
422

    
423
	log_error(sprintf(gettext("Message sent to %s OK"), $to));
424
	return;
425
}
426

    
427
/****f* notices/notify_via_growl
428
 * NAME
429
 *   notify_via_growl
430
 * INPUTS
431
 *	 notification string to send
432
 * RESULT
433
 *   returns true if message was sent
434
 ******/
435
function notify_via_growl($message, $force=false) {
436
	require_once("Net/Growl/Autoload.php");
437

    
438
	global $config, $g;
439

    
440
	if (isset($config['notifications']['growl']['disable']) && !$force) {
441
		return;
442
	}
443

    
444
	if (empty($config['notifications']['growl']['ipaddress'])) {
445
		return;
446
	}
447

    
448
	/* Do NOT send the same message twice */
449
	if (file_exists("/var/db/growlnotices_lastmsg.txt")) {
450
		$lastmsg = trim(file_get_contents("/var/db/growlnotices_lastmsg.txt"));
451
		if ($lastmsg == $message) {
452
			return;
453
		}
454
	}
455
	/* Store last message sent to avoid spamming */
456
	@file_put_contents("/var/db/growlnotices_lastmsg.txt", $message);
457

    
458
	if (!$force) {
459
		notify_via_queue_add($message, 'growl');
460
		return;
461
	}
462

    
463
	$ip = $config['notifications']['growl']['ipaddress'];
464

    
465
	if (!is_ipaddr($ip) && !(dns_check_record($ip, A) || dns_check_record($ip, AAAA))) {
466
		$err_msg = gettext(
467
		    "Growl IP Address is invalid. Check the setting in System Advanced Notifications.");
468
		log_error($err_msg);
469
		return($err_msg);
470
	}
471

    
472
	$hostname = $config['system']['hostname'] . "." . $config['system']['domain'];
473
	$password = $config['notifications']['growl']['password'];
474
	$name = $config['notifications']['growl']['name'];
475
	$notification = $config['notifications']['growl']['notification_name'];
476

    
477
	$options  = array(
478
		'host' => $ip,
479
		'protocol' => 'gntp',
480
		'timeout' => 20
481
	);
482

    
483
	try {
484
		$growl = Net_Growl::singleton($name, null, $password, $options);
485
		//$name = 'GROWL_NOTIFY_STATUS';
486
		$title = sprintf(gettext('%1$s (%2$s) - Notification'), $g['product_name'], $hostname);
487
		$growl->publish($name, $title, $message);
488
	} catch (Net_Growl_Exception $e) {
489
		$err_msg = sprintf(gettext(
490
		    'Could not send Growl notification to %1$s -- Error: %2$s'),
491
		    $ip, $e->getMessage());
492
		log_error($err_msg);
493
		return($err_msg);
494
	}
495

    
496
	return;
497
}
498

    
499
/****f* notices/register_via_growl
500
 * NAME
501
 *   register_via_growl
502
 * INPUTS
503
 *	 none
504
 * RESULT
505
 *   none
506
 ******/
507
function register_via_growl() {
508
	require_once("Net/Growl/Autoload.php");
509

    
510
	global $config;
511

    
512
	if (empty($config['notifications']['growl']['ipaddress'])) {
513
		return;
514
	}
515

    
516
	$ip = $config['notifications']['growl']['ipaddress'];
517

    
518
	if (!is_ipaddr($ip) && !(dns_check_record($ip, A) || dns_check_record($ip, AAAA))) {
519
		$err_msg = gettext(
520
		    "Growl IP Address is invalid. Check the setting in System Advanced Notifications.");
521
		log_error($err_msg);
522
		return($err_msg);
523
	}
524

    
525
	$name = $config['notifications']['growl']['name'];
526
	$password = $config['notifications']['growl']['password'];
527

    
528
	$app = new Net_Growl_Application(
529
		$name,
530
		null,
531
		$password
532
	);
533

    
534
	$options = array(
535
		'host' => $ip,
536
		'protocol' => 'gntp',
537
		'timeout' => 20
538
	);
539

    
540
	try {
541
		$growl = Net_Growl::singleton($app, null, null, $options);
542
		$growl->register();
543
	} catch (Net_Growl_Exception $e) {
544
		$err_msg = sprintf(gettext(
545
		    'Could not send register Growl on %1$s -- Error: %2$s'),
546
		    $ip, $e->getMessage());
547
		log_error($err_msg);
548
		return($err_msg);
549
	}
550

    
551
	return;
552
}
553

    
554
/* Notify via remote methods only - not via GUI. */
555
function notify_all_remote($msg) {
556
	notify_via_smtp($msg);
557
	notify_via_growl($msg);
558
}
559

    
560
?>
(31-31/60)