1#!/usr/bin/python
2from __future__ import (absolute_import, division, print_function)
3# Copyright 2019 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_dlp_filepattern
27short_description: Configure file patterns used by DLP blocking 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 dlp feature and filepattern category.
31      Examples include all parameters and values need to be adjusted to datasources before usage.
32      Tested with FOS v6.0.5
33version_added: "2.8"
34author:
35    - Miguel Angel Munoz (@mamunozgonzalez)
36    - Nicolas Thomas (@thomnico)
37notes:
38    - Requires fortiosapi library developed by Fortinet
39    - Run as a local_action in your playbook
40requirements:
41    - fortiosapi>=0.9.8
42options:
43    host:
44        description:
45            - FortiOS or FortiGate IP address.
46        type: str
47        required: false
48    username:
49        description:
50            - FortiOS or FortiGate username.
51        type: str
52        required: false
53    password:
54        description:
55            - FortiOS or FortiGate password.
56        type: str
57        default: ""
58    vdom:
59        description:
60            - Virtual domain, among those defined previously. A vdom is a
61              virtual instance of the FortiGate that can be configured and
62              used as a different unit.
63        type: str
64        default: root
65    https:
66        description:
67            - Indicates if the requests towards FortiGate must use HTTPS protocol.
68        type: bool
69        default: true
70    ssl_verify:
71        description:
72            - Ensures FortiGate certificate must be verified by a proper CA.
73        type: bool
74        default: true
75        version_added: 2.9
76    state:
77        description:
78            - Indicates whether to create or remove the object.
79              This attribute was present already in previous version in a deeper level.
80              It has been moved out to this outer level.
81        type: str
82        required: false
83        choices:
84            - present
85            - absent
86        version_added: 2.9
87    dlp_filepattern:
88        description:
89            - Configure file patterns used by DLP blocking.
90        default: null
91        type: dict
92        suboptions:
93            state:
94                description:
95                    - B(Deprecated)
96                    - Starting with Ansible 2.9 we recommend using the top-level 'state' parameter.
97                    - HORIZONTALLINE
98                    - Indicates whether to create or remove the object.
99                type: str
100                required: false
101                choices:
102                    - present
103                    - absent
104            comment:
105                description:
106                    - Optional comments.
107                type: str
108            entries:
109                description:
110                    - Configure file patterns used by DLP blocking.
111                type: list
112                suboptions:
113                    file_type:
114                        description:
115                            - Select a file type.
116                        type: str
117                        choices:
118                            - 7z
119                            - arj
120                            - cab
121                            - lzh
122                            - rar
123                            - tar
124                            - zip
125                            - bzip
126                            - gzip
127                            - bzip2
128                            - xz
129                            - bat
130                            - msc
131                            - uue
132                            - mime
133                            - base64
134                            - binhex
135                            - elf
136                            - exe
137                            - hta
138                            - html
139                            - jad
140                            - class
141                            - cod
142                            - javascript
143                            - msoffice
144                            - msofficex
145                            - fsg
146                            - upx
147                            - petite
148                            - aspack
149                            - sis
150                            - hlp
151                            - activemime
152                            - jpeg
153                            - gif
154                            - tiff
155                            - png
156                            - bmp
157                            - ignored
158                            - unknown
159                            - mpeg
160                            - mov
161                            - mp3
162                            - wma
163                            - wav
164                            - pdf
165                            - avi
166                            - rm
167                            - torrent
168                            - hibun
169                            - msi
170                            - mach-o
171                            - dmg
172                            - .net
173                            - xar
174                            - chm
175                            - iso
176                            - crx
177                    filter_type:
178                        description:
179                            - Filter by file name pattern or by file type.
180                        type: str
181                        choices:
182                            - pattern
183                            - type
184                    pattern:
185                        description:
186                            - Add a file name pattern.
187                        required: true
188                        type: str
189            id:
190                description:
191                    - ID.
192                required: true
193                type: int
194            name:
195                description:
196                    - Name of table containing the file pattern list.
197                type: str
198'''
199
200EXAMPLES = '''
201- hosts: localhost
202  vars:
203   host: "192.168.122.40"
204   username: "admin"
205   password: ""
206   vdom: "root"
207   ssl_verify: "False"
208  tasks:
209  - name: Configure file patterns used by DLP blocking.
210    fortios_dlp_filepattern:
211      host:  "{{ host }}"
212      username: "{{ username }}"
213      password: "{{ password }}"
214      vdom:  "{{ vdom }}"
215      https: "False"
216      state: "present"
217      dlp_filepattern:
218        comment: "Optional comments."
219        entries:
220         -
221            file_type: "7z"
222            filter_type: "pattern"
223            pattern: "<your_own_value>"
224        id:  "8"
225        name: "default_name_9"
226'''
227
228RETURN = '''
229build:
230  description: Build number of the fortigate image
231  returned: always
232  type: str
233  sample: '1547'
234http_method:
235  description: Last method used to provision the content into FortiGate
236  returned: always
237  type: str
238  sample: 'PUT'
239http_status:
240  description: Last result given by FortiGate on last operation applied
241  returned: always
242  type: str
243  sample: "200"
244mkey:
245  description: Master key (id) used in the last call to FortiGate
246  returned: success
247  type: str
248  sample: "id"
249name:
250  description: Name of the table used to fulfill the request
251  returned: always
252  type: str
253  sample: "urlfilter"
254path:
255  description: Path of the table used to fulfill the request
256  returned: always
257  type: str
258  sample: "webfilter"
259revision:
260  description: Internal revision number
261  returned: always
262  type: str
263  sample: "17.0.2.10658"
264serial:
265  description: Serial number of the unit
266  returned: always
267  type: str
268  sample: "FGVMEVYYQT3AB5352"
269status:
270  description: Indication of the operation's result
271  returned: always
272  type: str
273  sample: "success"
274vdom:
275  description: Virtual domain used
276  returned: always
277  type: str
278  sample: "root"
279version:
280  description: Version of the FortiGate
281  returned: always
282  type: str
283  sample: "v5.6.3"
284
285'''
286
287from ansible.module_utils.basic import AnsibleModule
288from ansible.module_utils.connection import Connection
289from ansible.module_utils.network.fortios.fortios import FortiOSHandler
290from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
291
292
293def login(data, fos):
294    host = data['host']
295    username = data['username']
296    password = data['password']
297    ssl_verify = data['ssl_verify']
298
299    fos.debug('on')
300    if 'https' in data and not data['https']:
301        fos.https('off')
302    else:
303        fos.https('on')
304
305    fos.login(host, username, password, verify=ssl_verify)
306
307
308def filter_dlp_filepattern_data(json):
309    option_list = ['comment', 'entries', 'id',
310                   'name']
311    dictionary = {}
312
313    for attribute in option_list:
314        if attribute in json and json[attribute] is not None:
315            dictionary[attribute] = json[attribute]
316
317    return dictionary
318
319
320def underscore_to_hyphen(data):
321    if isinstance(data, list):
322        for elem in data:
323            elem = underscore_to_hyphen(elem)
324    elif isinstance(data, dict):
325        new_data = {}
326        for k, v in data.items():
327            new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
328        data = new_data
329
330    return data
331
332
333def dlp_filepattern(data, fos):
334    vdom = data['vdom']
335    if 'state' in data and data['state']:
336        state = data['state']
337    elif 'state' in data['dlp_filepattern'] and data['dlp_filepattern']:
338        state = data['dlp_filepattern']['state']
339    else:
340        state = True
341    dlp_filepattern_data = data['dlp_filepattern']
342    filtered_data = underscore_to_hyphen(filter_dlp_filepattern_data(dlp_filepattern_data))
343
344    if state == "present":
345        return fos.set('dlp',
346                       'filepattern',
347                       data=filtered_data,
348                       vdom=vdom)
349
350    elif state == "absent":
351        return fos.delete('dlp',
352                          'filepattern',
353                          mkey=filtered_data['id'],
354                          vdom=vdom)
355
356
357def is_successful_status(status):
358    return status['status'] == "success" or \
359        status['http_method'] == "DELETE" and status['http_status'] == 404
360
361
362def fortios_dlp(data, fos):
363
364    if data['dlp_filepattern']:
365        resp = dlp_filepattern(data, fos)
366
367    return not is_successful_status(resp), \
368        resp['status'] == "success", \
369        resp
370
371
372def main():
373    fields = {
374        "host": {"required": False, "type": "str"},
375        "username": {"required": False, "type": "str"},
376        "password": {"required": False, "type": "str", "default": "", "no_log": True},
377        "vdom": {"required": False, "type": "str", "default": "root"},
378        "https": {"required": False, "type": "bool", "default": True},
379        "ssl_verify": {"required": False, "type": "bool", "default": True},
380        "state": {"required": False, "type": "str",
381                  "choices": ["present", "absent"]},
382        "dlp_filepattern": {
383            "required": False, "type": "dict", "default": None,
384            "options": {
385                "state": {"required": False, "type": "str",
386                          "choices": ["present", "absent"]},
387                "comment": {"required": False, "type": "str"},
388                "entries": {"required": False, "type": "list",
389                            "options": {
390                                "file_type": {"required": False, "type": "str",
391                                              "choices": ["7z", "arj", "cab",
392                                                          "lzh", "rar", "tar",
393                                                          "zip", "bzip", "gzip",
394                                                          "bzip2", "xz", "bat",
395                                                          "msc", "uue", "mime",
396                                                          "base64", "binhex", "elf",
397                                                          "exe", "hta", "html",
398                                                          "jad", "class", "cod",
399                                                          "javascript", "msoffice", "msofficex",
400                                                          "fsg", "upx", "petite",
401                                                          "aspack", "sis", "hlp",
402                                                          "activemime", "jpeg", "gif",
403                                                          "tiff", "png", "bmp",
404                                                          "ignored", "unknown", "mpeg",
405                                                          "mov", "mp3", "wma",
406                                                          "wav", "pdf", "avi",
407                                                          "rm", "torrent", "hibun",
408                                                          "msi", "mach-o", "dmg",
409                                                          ".net", "xar", "chm",
410                                                          "iso", "crx"]},
411                                "filter_type": {"required": False, "type": "str",
412                                                "choices": ["pattern", "type"]},
413                                "pattern": {"required": True, "type": "str"}
414                            }},
415                "id": {"required": True, "type": "int"},
416                "name": {"required": False, "type": "str"}
417
418            }
419        }
420    }
421
422    module = AnsibleModule(argument_spec=fields,
423                           supports_check_mode=False)
424
425    # legacy_mode refers to using fortiosapi instead of HTTPAPI
426    legacy_mode = 'host' in module.params and module.params['host'] is not None and \
427                  'username' in module.params and module.params['username'] is not None and \
428                  'password' in module.params and module.params['password'] is not None
429
430    if not legacy_mode:
431        if module._socket_path:
432            connection = Connection(module._socket_path)
433            fos = FortiOSHandler(connection)
434
435            is_error, has_changed, result = fortios_dlp(module.params, fos)
436        else:
437            module.fail_json(**FAIL_SOCKET_MSG)
438    else:
439        try:
440            from fortiosapi import FortiOSAPI
441        except ImportError:
442            module.fail_json(msg="fortiosapi module is required")
443
444        fos = FortiOSAPI()
445
446        login(module.params, fos)
447        is_error, has_changed, result = fortios_dlp(module.params, fos)
448        fos.logout()
449
450    if not is_error:
451        module.exit_json(changed=has_changed, meta=result)
452    else:
453        module.fail_json(msg="Error in repo", meta=result)
454
455
456if __name__ == '__main__':
457    main()
458