1#!/usr/local/bin/python3.8
2from __future__ import (absolute_import, division, print_function)
3# Copyright 2019-2020 Fortinet, Inc.
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
18__metaclass__ = type
19
20ANSIBLE_METADATA = {'status': ['preview'],
21                    'supported_by': 'community',
22                    'metadata_version': '1.1'}
23
24DOCUMENTATION = '''
25---
26module: fortios_antivirus_settings
27short_description: Configure AntiVirus settings in Fortinet's FortiOS and FortiGate.
28description:
29    - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
30      user to set and modify antivirus feature and settings category.
31      Examples include all parameters and values need to be adjusted to datasources before usage.
32      Tested with FOS v6.0.0
33version_added: "2.10"
34author:
35    - Link Zheng (@chillancezen)
36    - Jie Xue (@JieX19)
37    - Hongbin Lu (@fgtdev-hblu)
38    - Frank Shen (@frankshen01)
39    - Miguel Angel Munoz (@mamunozgonzalez)
40    - Nicolas Thomas (@thomnico)
41notes:
42    - Legacy fortiosapi has been deprecated, httpapi is the preferred way to run playbooks
43
44requirements:
45    - ansible>=2.9.0
46options:
47    access_token:
48        description:
49            - Token-based authentication.
50              Generated from GUI of Fortigate.
51        type: str
52        required: false
53    enable_log:
54        description:
55            - Enable/Disable logging for task.
56        type: bool
57        required: false
58        default: false
59    vdom:
60        description:
61            - Virtual domain, among those defined previously. A vdom is a
62              virtual instance of the FortiGate that can be configured and
63              used as a different unit.
64        type: str
65        default: root
66
67    antivirus_settings:
68        description:
69            - Configure AntiVirus settings.
70        default: null
71        type: dict
72        suboptions:
73            default_db:
74                description:
75                    - Select the AV database to be used for AV scanning.
76                type: str
77                choices:
78                    - normal
79                    - extended
80                    - extreme
81            grayware:
82                description:
83                    - Enable/disable grayware detection when an AntiVirus profile is applied to traffic.
84                type: str
85                choices:
86                    - enable
87                    - disable
88            machine_learning_detection:
89                description:
90                    - Use machine learning based malware detection.
91                type: str
92                choices:
93                    - enable
94                    - monitor
95                    - disable
96            override_timeout:
97                description:
98                    - Override the large file scan timeout value in seconds (30 - 3600). Zero is the default value and is used to disable this command. When
99                       disabled, the daemon adjusts the large file scan timeout based on the file size.
100                type: int
101            use_extreme_db:
102                description:
103                    - Enable/disable the use of Extreme AVDB.
104                type: str
105                choices:
106                    - enable
107                    - disable
108'''
109
110EXAMPLES = '''
111- hosts: fortigates
112  collections:
113    - fortinet.fortios
114  connection: httpapi
115  vars:
116   vdom: "root"
117   ansible_httpapi_use_ssl: yes
118   ansible_httpapi_validate_certs: no
119   ansible_httpapi_port: 443
120  tasks:
121  - name: Configure AntiVirus settings.
122    fortios_antivirus_settings:
123      vdom:  "{{ vdom }}"
124      antivirus_settings:
125        default_db: "normal"
126        grayware: "enable"
127        machine_learning_detection: "enable"
128        override_timeout: "6"
129        use_extreme_db: "enable"
130
131'''
132
133RETURN = '''
134build:
135  description: Build number of the fortigate image
136  returned: always
137  type: str
138  sample: '1547'
139http_method:
140  description: Last method used to provision the content into FortiGate
141  returned: always
142  type: str
143  sample: 'PUT'
144http_status:
145  description: Last result given by FortiGate on last operation applied
146  returned: always
147  type: str
148  sample: "200"
149mkey:
150  description: Master key (id) used in the last call to FortiGate
151  returned: success
152  type: str
153  sample: "id"
154name:
155  description: Name of the table used to fulfill the request
156  returned: always
157  type: str
158  sample: "urlfilter"
159path:
160  description: Path of the table used to fulfill the request
161  returned: always
162  type: str
163  sample: "webfilter"
164revision:
165  description: Internal revision number
166  returned: always
167  type: str
168  sample: "17.0.2.10658"
169serial:
170  description: Serial number of the unit
171  returned: always
172  type: str
173  sample: "FGVMEVYYQT3AB5352"
174status:
175  description: Indication of the operation's result
176  returned: always
177  type: str
178  sample: "success"
179vdom:
180  description: Virtual domain used
181  returned: always
182  type: str
183  sample: "root"
184version:
185  description: Version of the FortiGate
186  returned: always
187  type: str
188  sample: "v5.6.3"
189
190'''
191from ansible.module_utils.basic import AnsibleModule
192from ansible.module_utils.connection import Connection
193from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import FortiOSHandler
194from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_legacy_fortiosapi
195from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import schema_to_module_spec
196from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_schema_versioning
197from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
198from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import is_same_comparison
199from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import serialize
200
201
202def filter_antivirus_settings_data(json):
203    option_list = ['default_db', 'grayware', 'machine_learning_detection',
204                   'override_timeout', 'use_extreme_db']
205    dictionary = {}
206
207    for attribute in option_list:
208        if attribute in json and json[attribute] is not None:
209            dictionary[attribute] = json[attribute]
210
211    return dictionary
212
213
214def underscore_to_hyphen(data):
215    if isinstance(data, list):
216        for i, elem in enumerate(data):
217            data[i] = underscore_to_hyphen(elem)
218    elif isinstance(data, dict):
219        new_data = {}
220        for k, v in data.items():
221            new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
222        data = new_data
223
224    return data
225
226
227def antivirus_settings(data, fos):
228    vdom = data['vdom']
229    antivirus_settings_data = data['antivirus_settings']
230    filtered_data = underscore_to_hyphen(filter_antivirus_settings_data(antivirus_settings_data))
231
232    return fos.set('antivirus',
233                   'settings',
234                   data=filtered_data,
235                   vdom=vdom)
236
237
238def is_successful_status(status):
239    return status['status'] == "success" or \
240        status['http_method'] == "DELETE" and status['http_status'] == 404
241
242
243def fortios_antivirus(data, fos):
244
245    if data['antivirus_settings']:
246        resp = antivirus_settings(data, fos)
247    else:
248        fos._module.fail_json(msg='missing task body: %s' % ('antivirus_settings'))
249
250    return not is_successful_status(resp), \
251        resp['status'] == "success" and \
252        (resp['revision_changed'] if 'revision_changed' in resp else True), \
253        resp
254
255
256versioned_schema = {
257    "type": "dict",
258    "children": {
259        "override_timeout": {
260            "type": "integer",
261            "revisions": {
262                "v6.0.0": True,
263                "v7.0.0": True,
264                "v6.0.5": True,
265                "v6.4.4": True,
266                "v6.4.0": True,
267                "v6.4.1": True,
268                "v6.2.0": True,
269                "v6.2.3": True,
270                "v6.2.5": True,
271                "v6.2.7": True,
272                "v6.0.11": True
273            }
274        },
275        "machine_learning_detection": {
276            "type": "string",
277            "options": [
278                {
279                    "value": "enable",
280                    "revisions": {
281                        "v7.0.0": True
282                    }
283                },
284                {
285                    "value": "monitor",
286                    "revisions": {
287                        "v7.0.0": True
288                    }
289                },
290                {
291                    "value": "disable",
292                    "revisions": {
293                        "v7.0.0": True
294                    }
295                }
296            ],
297            "revisions": {
298                "v7.0.0": True
299            }
300        },
301        "use_extreme_db": {
302            "type": "string",
303            "options": [
304                {
305                    "value": "enable",
306                    "revisions": {
307                        "v6.4.4": True,
308                        "v7.0.0": True,
309                        "v6.4.0": True,
310                        "v6.4.1": True
311                    }
312                },
313                {
314                    "value": "disable",
315                    "revisions": {
316                        "v6.4.4": True,
317                        "v7.0.0": True,
318                        "v6.4.0": True,
319                        "v6.4.1": True
320                    }
321                }
322            ],
323            "revisions": {
324                "v6.4.4": True,
325                "v7.0.0": True,
326                "v6.4.0": True,
327                "v6.4.1": True
328            }
329        },
330        "default_db": {
331            "type": "string",
332            "options": [
333                {
334                    "value": "normal",
335                    "revisions": {
336                        "v6.0.0": True,
337                        "v6.0.5": True,
338                        "v6.2.0": True,
339                        "v6.2.3": True,
340                        "v6.2.5": True,
341                        "v6.2.7": True,
342                        "v6.0.11": True
343                    }
344                },
345                {
346                    "value": "extended",
347                    "revisions": {
348                        "v6.0.0": True,
349                        "v6.0.5": True,
350                        "v6.2.0": True,
351                        "v6.2.3": True,
352                        "v6.2.5": True,
353                        "v6.2.7": True,
354                        "v6.0.11": True
355                    }
356                },
357                {
358                    "value": "extreme",
359                    "revisions": {
360                        "v6.0.0": True,
361                        "v6.0.5": True,
362                        "v6.2.0": True,
363                        "v6.2.3": True,
364                        "v6.2.5": True,
365                        "v6.2.7": True,
366                        "v6.0.11": True
367                    }
368                }
369            ],
370            "revisions": {
371                "v6.0.0": True,
372                "v7.0.0": False,
373                "v6.0.5": True,
374                "v6.4.4": False,
375                "v6.4.0": False,
376                "v6.4.1": False,
377                "v6.2.0": True,
378                "v6.2.3": True,
379                "v6.2.5": True,
380                "v6.2.7": True,
381                "v6.0.11": True
382            }
383        },
384        "grayware": {
385            "type": "string",
386            "options": [
387                {
388                    "value": "enable",
389                    "revisions": {
390                        "v6.0.0": True,
391                        "v7.0.0": True,
392                        "v6.0.5": True,
393                        "v6.4.4": True,
394                        "v6.4.0": True,
395                        "v6.4.1": True,
396                        "v6.2.0": True,
397                        "v6.2.3": True,
398                        "v6.2.5": True,
399                        "v6.2.7": True,
400                        "v6.0.11": True
401                    }
402                },
403                {
404                    "value": "disable",
405                    "revisions": {
406                        "v6.0.0": True,
407                        "v7.0.0": True,
408                        "v6.0.5": True,
409                        "v6.4.4": True,
410                        "v6.4.0": True,
411                        "v6.4.1": True,
412                        "v6.2.0": True,
413                        "v6.2.3": True,
414                        "v6.2.5": True,
415                        "v6.2.7": True,
416                        "v6.0.11": True
417                    }
418                }
419            ],
420            "revisions": {
421                "v6.0.0": True,
422                "v7.0.0": True,
423                "v6.0.5": True,
424                "v6.4.4": True,
425                "v6.4.0": True,
426                "v6.4.1": True,
427                "v6.2.0": True,
428                "v6.2.3": True,
429                "v6.2.5": True,
430                "v6.2.7": True,
431                "v6.0.11": True
432            }
433        }
434    },
435    "revisions": {
436        "v6.0.0": True,
437        "v7.0.0": True,
438        "v6.0.5": True,
439        "v6.4.4": True,
440        "v6.4.0": True,
441        "v6.4.1": True,
442        "v6.2.0": True,
443        "v6.2.3": True,
444        "v6.2.5": True,
445        "v6.2.7": True,
446        "v6.0.11": True
447    }
448}
449
450
451def main():
452    module_spec = schema_to_module_spec(versioned_schema)
453    mkeyname = None
454    fields = {
455        "access_token": {"required": False, "type": "str", "no_log": True},
456        "enable_log": {"required": False, "type": bool},
457        "vdom": {"required": False, "type": "str", "default": "root"},
458        "antivirus_settings": {
459            "required": False, "type": "dict", "default": None,
460            "options": {
461            }
462        }
463    }
464    for attribute_name in module_spec['options']:
465        fields["antivirus_settings"]['options'][attribute_name] = module_spec['options'][attribute_name]
466        if mkeyname and mkeyname == attribute_name:
467            fields["antivirus_settings"]['options'][attribute_name]['required'] = True
468
469    check_legacy_fortiosapi()
470    module = AnsibleModule(argument_spec=fields,
471                           supports_check_mode=False)
472
473    versions_check_result = None
474    if module._socket_path:
475        connection = Connection(module._socket_path)
476        if 'access_token' in module.params:
477            connection.set_option('access_token', module.params['access_token'])
478
479        if 'enable_log' in module.params:
480            connection.set_option('enable_log', module.params['enable_log'])
481        else:
482            connection.set_option('enable_log', False)
483        fos = FortiOSHandler(connection, module, mkeyname)
484        versions_check_result = check_schema_versioning(fos, versioned_schema, "antivirus_settings")
485
486        is_error, has_changed, result = fortios_antivirus(module.params, fos)
487
488    else:
489        module.fail_json(**FAIL_SOCKET_MSG)
490
491    if versions_check_result and versions_check_result['matched'] is False:
492        module.warn("Ansible has detected version mismatch between FortOS system and your playbook, see more details by specifying option -vvv")
493
494    if not is_error:
495        if versions_check_result and versions_check_result['matched'] is False:
496            module.exit_json(changed=has_changed, version_check_warning=versions_check_result, meta=result)
497        else:
498            module.exit_json(changed=has_changed, meta=result)
499    else:
500        if versions_check_result and versions_check_result['matched'] is False:
501            module.fail_json(msg="Error in repo", version_check_warning=versions_check_result, meta=result)
502        else:
503            module.fail_json(msg="Error in repo", meta=result)
504
505
506if __name__ == '__main__':
507    main()
508