Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * Base class for antivirus integration.
19
 *
20
 * @package    core_antivirus
21
 * @copyright  2015 Ruslan Kabalin, Lancaster University.
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
namespace core\antivirus;
26
 
27
defined('MOODLE_INTERNAL') || die();
28
require_once($CFG->dirroot . '/iplookup/lib.php');
29
 
30
/**
31
 * Base abstract antivirus scanner class.
32
 *
33
 * @package    core
34
 * @subpackage antivirus
35
 * @copyright  2015 Ruslan Kabalin, Lancaster University.
36
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37
 */
38
abstract class scanner {
39
    /** Scanning result indicating no virus found. */
40
    const SCAN_RESULT_OK = 0;
41
    /** Scanning result indicating that virus is found. */
42
    const SCAN_RESULT_FOUND = 1;
43
    /** Scanning result indicating the error. */
44
    const SCAN_RESULT_ERROR = 2;
45
 
46
    /** @var \stdClass the config for antivirus */
47
    protected $config;
48
    /** @var string scanning notice */
49
    protected $scanningnotice = '';
50
    /** @var array any admin messages generated by a plugin. */
51
    protected $messages = [];
52
 
53
    /**
54
     * Class constructor.
55
     *
56
     * @return void.
57
     */
58
    public function __construct() {
59
        // Populate config variable, inheriting class namespace is matching
60
        // full plugin name, so we can use it directly to retrieve plugin
61
        // configuration.
62
        $ref = new \ReflectionClass(get_class($this));
63
        $this->config = get_config($ref->getNamespaceName());
64
    }
65
 
66
    /**
67
     * Config get method.
68
     *
69
     * @param string $property config property to get.
70
     * @return mixed
71
     * @throws \coding_exception
72
     */
73
    public function get_config($property) {
74
        if (property_exists($this->config, $property)) {
75
            return $this->config->$property;
76
        }
77
        throw new \coding_exception('Config property "' . $property . '" doesn\'t exist');
78
    }
79
 
80
    /**
81
     * Get scanning notice.
82
     *
83
     * @return string
84
     */
85
    public function get_scanning_notice() {
86
        return $this->scanningnotice;
87
    }
88
 
89
    /**
90
     * Set scanning notice.
91
     *
92
     * @param string $notice notice to set.
93
     * @return void
94
     */
95
    protected function set_scanning_notice($notice) {
96
        $this->scanningnotice = $notice;
97
    }
98
 
99
    /**
100
     * Are the antivirus settings configured?
101
     *
102
     * @return bool True if plugin has been configured.
103
     */
104
    abstract public function is_configured();
105
 
106
    /**
107
     * Scan file.
108
     *
109
     * @param string $file Full path to the file.
110
     * @param string $filename Name of the file (could be different from physical file if temp file is used).
111
     * @return int Scanning result constants.
112
     */
113
    abstract public function scan_file($file, $filename);
114
 
115
    /**
116
     * Scan data.
117
     *
118
     * By default it saves data variable content to file and then scans it using
119
     * scan_file method, however if antivirus plugin permits scanning data directly,
120
     * the method can be overridden.
121
     *
122
     * @param string $data The variable containing the data to scan.
123
     * @return int Scanning result constants.
124
     */
125
    public function scan_data($data) {
126
        // Prepare temp file.
127
        $tempdir = make_request_directory();
128
        $tempfile = $tempdir . DIRECTORY_SEPARATOR . rand();
129
        file_put_contents($tempfile, $data);
130
 
131
        // Perform a virus scan now.
132
        return $this->scan_file($tempfile, get_string('datastream', 'antivirus'));
133
    }
134
 
135
    /**
136
     * This function pushes given messages into the message queue, which will be sent by the antivirus manager.
137
     *
138
     * @param string $notice The body of the email to be sent.
139
     * @param string $format The body format.
140
     * @param string $eventname event name
141
     * @return void
142
     * @throws \coding_exception
143
     * @throws \moodle_exception
144
     */
145
    public function message_admins($notice, $format = FORMAT_PLAIN, $eventname = 'errors') {
146
        $noticehtml = $format !== FORMAT_PLAIN ? format_text($notice, $format) : '';
147
        $site = get_site();
148
 
149
        $subject = get_string('emailsubject', 'antivirus', format_string($site->fullname));
150
        $notifyemail = get_config('antivirus', 'notifyemail');
151
        // If one email address is specified, construct a message to fake account.
152
        if (!empty($notifyemail)) {
153
            $user = new \stdClass();
154
            $user->id = -1;
155
            $user->email = $notifyemail;
156
            $user->mailformat = 1;
157
            $admins = [$user];
158
        } else {
159
            // Otherwise, we message all admins.
160
            $admins = get_admins();
161
        }
162
 
163
        foreach ($admins as $admin) {
164
            $eventdata = new \core\message\message();
165
            $eventdata->courseid          = SITEID;
166
            $eventdata->component         = 'moodle';
167
            $eventdata->name              = $eventname;
168
            $eventdata->userfrom          = get_admin();
169
            $eventdata->userto            = $admin;
170
            $eventdata->subject           = $subject;
171
            $eventdata->fullmessage       = $notice;
172
            $eventdata->fullmessageformat = $format;
173
            $eventdata->fullmessagehtml   = $noticehtml;
174
            $eventdata->smallmessage      = '';
175
 
176
            // Now add the message to an array to be sent by the antivirus manager.
177
            $this->messages[] = $eventdata;
178
        }
179
    }
180
 
181
    /**
182
     * Return incident details
183
     *
184
     * @param string $file full path to the file
185
     * @param string $filename original name of the file
186
     * @param string $notice notice from antivirus
187
     * @param string $virus if this template is due to a virus found.
188
     * @return string the incident details
189
     * @throws \coding_exception
190
     */
191
    public function get_incident_details($file = '', $filename = '', $notice = '', $virus = true) {
192
        global $OUTPUT, $USER;
193
        if (empty($notice)) {
194
            $notice = $this->get_scanning_notice();
195
        }
196
        $classname = get_class($this);
197
        $component = explode('\\', $classname)[0];
198
 
199
        $content = new \stdClass();
200
        $unknown = get_string('unknown', 'antivirus');
201
        $content->header = get_string('emailinfectedfiledetected', 'antivirus');
202
        $content->filename = !empty($filename) ? $filename : $unknown;
203
        $content->scanner = $component;
204
        // Check for empty file, or file not uploaded.
205
        if (!empty($file) && filesize($file) !== false) {
206
            $content->filesize = display_size(filesize($file));
207
            $content->contenthash = \file_storage::hash_from_path($file);
208
            $content->contenttype = mime_content_type($file);
209
        } else {
210
            $content->filesize = $unknown;
211
            $content->contenthash = $unknown;
212
            $content->contenttype = $unknown;
213
        }
214
 
215
        $content->author = \core_user::is_real_user($USER->id) ? fullname($USER) . " ($USER->username)" : $unknown;
216
        $content->ipaddress = getremoteaddr();
217
        $geoinfo = iplookup_find_location(getremoteaddr());
218
        $content->geoinfo = $geoinfo['city'] . ', ' . $geoinfo['country'];
219
        $content->date = userdate(time(), get_string('strftimedatetimeshort'));
220
        $content->referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $unknown;
221
        $content->notice = $notice;
222
        $report = new \moodle_url('/report/infectedfiles/index.php');
223
        $content->report = $report->out();
224
 
225
        // If this is not due to a virus, we need to change the header line.
226
        if (!$virus) {
227
            $content->header = get_string('emailscannererrordetected', 'antivirus');
228
        }
229
 
230
        return $OUTPUT->render_from_template('core/infected_file_email', $content);
231
    }
232
 
233
    /**
234
     * Getter method for messages queued by the antivirus scanner.
235
     *
236
     * @return array
237
     */
238
    public function get_messages(): array {
239
        return $this->messages;
240
    }
241
 
242
    /**
243
     * Getter method for the antivirus message displayed in the exception.
244
     *
245
     * @return array array of string and component to pass to exception constructor.
246
     */
247
    public function get_virus_found_message() {
248
        // Base antivirus found string.
249
        return ['string' => 'virusfound', 'component' => 'antivirus', 'placeholders' => []];
250
    }
251
}