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_system_email_server
27short_description: Configure the email server used by the FortiGate various things. For example, for sending email messages to users to support user
28   authentication features in Fortinet's FortiOS and FortiGate.
29description:
30    - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
31      user to set and modify system feature and email_server category.
32      Examples include all parameters and values need to be adjusted to datasources before usage.
33      Tested with FOS v6.0.0
34version_added: "2.10"
35author:
36    - Link Zheng (@chillancezen)
37    - Jie Xue (@JieX19)
38    - Hongbin Lu (@fgtdev-hblu)
39    - Frank Shen (@frankshen01)
40    - Miguel Angel Munoz (@mamunozgonzalez)
41    - Nicolas Thomas (@thomnico)
42notes:
43    - Legacy fortiosapi has been deprecated, httpapi is the preferred way to run playbooks
44
45requirements:
46    - ansible>=2.9.0
47options:
48    access_token:
49        description:
50            - Token-based authentication.
51              Generated from GUI of Fortigate.
52        type: str
53        required: false
54    enable_log:
55        description:
56            - Enable/Disable logging for task.
57        type: bool
58        required: false
59        default: false
60    vdom:
61        description:
62            - Virtual domain, among those defined previously. A vdom is a
63              virtual instance of the FortiGate that can be configured and
64              used as a different unit.
65        type: str
66        default: root
67
68    system_email_server:
69        description:
70            - Configure the email server used by the FortiGate various things. For example, for sending email messages to users to support user authentication
71               features.
72        default: null
73        type: dict
74        suboptions:
75            authenticate:
76                description:
77                    - Enable/disable authentication.
78                type: str
79                choices:
80                    - enable
81                    - disable
82            interface:
83                description:
84                    - Specify outgoing interface to reach server. Source system.interface.name.
85                type: str
86            interface_select_method:
87                description:
88                    - Specify how to select outgoing interface to reach server.
89                type: str
90                choices:
91                    - auto
92                    - sdwan
93                    - specify
94            password:
95                description:
96                    - SMTP server user password for authentication.
97                type: str
98            port:
99                description:
100                    - SMTP server port.
101                type: int
102            reply_to:
103                description:
104                    - Reply-To email address.
105                type: str
106            security:
107                description:
108                    - Connection security used by the email server.
109                type: str
110                choices:
111                    - none
112                    - starttls
113                    - smtps
114            server:
115                description:
116                    - SMTP server IP address or hostname.
117                type: str
118            source_ip:
119                description:
120                    - SMTP server IPv4 source IP.
121                type: str
122            source_ip6:
123                description:
124                    - SMTP server IPv6 source IP.
125                type: str
126            ssl_min_proto_version:
127                description:
128                    - Minimum supported protocol version for SSL/TLS connections .
129                type: str
130                choices:
131                    - default
132                    - SSLv3
133                    - TLSv1
134                    - TLSv1-1
135                    - TLSv1-2
136            type:
137                description:
138                    - Use FortiGuard Message service or custom email server.
139                type: str
140                choices:
141                    - custom
142            username:
143                description:
144                    - SMTP server user name for authentication.
145                type: str
146            validate_server:
147                description:
148                    - Enable/disable validation of server certificate.
149                type: str
150                choices:
151                    - enable
152                    - disable
153'''
154
155EXAMPLES = '''
156- hosts: fortigates
157  collections:
158    - fortinet.fortios
159  connection: httpapi
160  vars:
161   vdom: "root"
162   ansible_httpapi_use_ssl: yes
163   ansible_httpapi_validate_certs: no
164   ansible_httpapi_port: 443
165  tasks:
166  - name: Configure the email server used by the FortiGate various things. For example, for sending email messages to users to support user authentication
167     features.
168    fortios_system_email_server:
169      vdom:  "{{ vdom }}"
170      system_email_server:
171        authenticate: "enable"
172        interface: "<your_own_value> (source system.interface.name)"
173        interface_select_method: "auto"
174        password: "<your_own_value>"
175        port: "7"
176        reply_to: "<your_own_value>"
177        security: "none"
178        server: "192.168.100.40"
179        source_ip: "84.230.14.43"
180        source_ip6: "<your_own_value>"
181        ssl_min_proto_version: "default"
182        type: "custom"
183        username: "<your_own_value>"
184        validate_server: "enable"
185
186'''
187
188RETURN = '''
189build:
190  description: Build number of the fortigate image
191  returned: always
192  type: str
193  sample: '1547'
194http_method:
195  description: Last method used to provision the content into FortiGate
196  returned: always
197  type: str
198  sample: 'PUT'
199http_status:
200  description: Last result given by FortiGate on last operation applied
201  returned: always
202  type: str
203  sample: "200"
204mkey:
205  description: Master key (id) used in the last call to FortiGate
206  returned: success
207  type: str
208  sample: "id"
209name:
210  description: Name of the table used to fulfill the request
211  returned: always
212  type: str
213  sample: "urlfilter"
214path:
215  description: Path of the table used to fulfill the request
216  returned: always
217  type: str
218  sample: "webfilter"
219revision:
220  description: Internal revision number
221  returned: always
222  type: str
223  sample: "17.0.2.10658"
224serial:
225  description: Serial number of the unit
226  returned: always
227  type: str
228  sample: "FGVMEVYYQT3AB5352"
229status:
230  description: Indication of the operation's result
231  returned: always
232  type: str
233  sample: "success"
234vdom:
235  description: Virtual domain used
236  returned: always
237  type: str
238  sample: "root"
239version:
240  description: Version of the FortiGate
241  returned: always
242  type: str
243  sample: "v5.6.3"
244
245'''
246from ansible.module_utils.basic import AnsibleModule
247from ansible.module_utils.connection import Connection
248from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import FortiOSHandler
249from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_legacy_fortiosapi
250from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import schema_to_module_spec
251from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_schema_versioning
252from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
253from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import is_same_comparison
254from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import serialize
255
256
257def filter_system_email_server_data(json):
258    option_list = ['authenticate', 'interface', 'interface_select_method',
259                   'password', 'port', 'reply_to',
260                   'security', 'server', 'source_ip',
261                   'source_ip6', 'ssl_min_proto_version', 'type',
262                   'username', 'validate_server']
263    dictionary = {}
264
265    for attribute in option_list:
266        if attribute in json and json[attribute] is not None:
267            dictionary[attribute] = json[attribute]
268
269    return dictionary
270
271
272def underscore_to_hyphen(data):
273    if isinstance(data, list):
274        for i, elem in enumerate(data):
275            data[i] = underscore_to_hyphen(elem)
276    elif isinstance(data, dict):
277        new_data = {}
278        for k, v in data.items():
279            new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
280        data = new_data
281
282    return data
283
284
285def system_email_server(data, fos):
286    vdom = data['vdom']
287    system_email_server_data = data['system_email_server']
288    filtered_data = underscore_to_hyphen(filter_system_email_server_data(system_email_server_data))
289
290    return fos.set('system',
291                   'email-server',
292                   data=filtered_data,
293                   vdom=vdom)
294
295
296def is_successful_status(status):
297    return status['status'] == "success" or \
298        status['http_method'] == "DELETE" and status['http_status'] == 404
299
300
301def fortios_system(data, fos):
302
303    if data['system_email_server']:
304        resp = system_email_server(data, fos)
305    else:
306        fos._module.fail_json(msg='missing task body: %s' % ('system_email_server'))
307
308    return not is_successful_status(resp), \
309        resp['status'] == "success" and \
310        (resp['revision_changed'] if 'revision_changed' in resp else True), \
311        resp
312
313
314versioned_schema = {
315    "type": "dict",
316    "children": {
317        "username": {
318            "type": "string",
319            "revisions": {
320                "v6.0.0": True,
321                "v7.0.0": True,
322                "v6.0.5": True,
323                "v6.4.4": True,
324                "v6.4.0": True,
325                "v6.4.1": True,
326                "v6.2.0": True,
327                "v6.2.3": True,
328                "v6.2.5": True,
329                "v6.2.7": True,
330                "v6.0.11": True
331            }
332        },
333        "authenticate": {
334            "type": "string",
335            "options": [
336                {
337                    "value": "enable",
338                    "revisions": {
339                        "v6.0.0": True,
340                        "v7.0.0": True,
341                        "v6.0.5": True,
342                        "v6.4.4": True,
343                        "v6.4.0": True,
344                        "v6.4.1": True,
345                        "v6.2.0": True,
346                        "v6.2.3": True,
347                        "v6.2.5": True,
348                        "v6.2.7": True,
349                        "v6.0.11": True
350                    }
351                },
352                {
353                    "value": "disable",
354                    "revisions": {
355                        "v6.0.0": True,
356                        "v7.0.0": True,
357                        "v6.0.5": True,
358                        "v6.4.4": True,
359                        "v6.4.0": True,
360                        "v6.4.1": True,
361                        "v6.2.0": True,
362                        "v6.2.3": True,
363                        "v6.2.5": True,
364                        "v6.2.7": True,
365                        "v6.0.11": True
366                    }
367                }
368            ],
369            "revisions": {
370                "v6.0.0": True,
371                "v7.0.0": True,
372                "v6.0.5": True,
373                "v6.4.4": True,
374                "v6.4.0": True,
375                "v6.4.1": True,
376                "v6.2.0": True,
377                "v6.2.3": True,
378                "v6.2.5": True,
379                "v6.2.7": True,
380                "v6.0.11": True
381            }
382        },
383        "source_ip": {
384            "type": "string",
385            "revisions": {
386                "v6.0.0": True,
387                "v7.0.0": True,
388                "v6.0.5": True,
389                "v6.4.4": True,
390                "v6.4.0": True,
391                "v6.4.1": True,
392                "v6.2.0": True,
393                "v6.2.3": True,
394                "v6.2.5": True,
395                "v6.2.7": True,
396                "v6.0.11": True
397            }
398        },
399        "server": {
400            "type": "string",
401            "revisions": {
402                "v6.0.0": True,
403                "v7.0.0": True,
404                "v6.0.5": True,
405                "v6.4.4": True,
406                "v6.4.0": True,
407                "v6.4.1": True,
408                "v6.2.0": True,
409                "v6.2.3": True,
410                "v6.2.5": True,
411                "v6.2.7": True,
412                "v6.0.11": True
413            }
414        },
415        "reply_to": {
416            "type": "string",
417            "revisions": {
418                "v6.0.0": True,
419                "v7.0.0": True,
420                "v6.0.5": True,
421                "v6.4.4": True,
422                "v6.4.0": True,
423                "v6.4.1": True,
424                "v6.2.0": True,
425                "v6.2.3": True,
426                "v6.2.5": True,
427                "v6.2.7": True,
428                "v6.0.11": True
429            }
430        },
431        "source_ip6": {
432            "type": "string",
433            "revisions": {
434                "v6.0.0": True,
435                "v7.0.0": True,
436                "v6.0.5": True,
437                "v6.4.4": True,
438                "v6.4.0": True,
439                "v6.4.1": True,
440                "v6.2.0": True,
441                "v6.2.3": True,
442                "v6.2.5": True,
443                "v6.2.7": True,
444                "v6.0.11": True
445            }
446        },
447        "ssl_min_proto_version": {
448            "type": "string",
449            "options": [
450                {
451                    "value": "default",
452                    "revisions": {
453                        "v6.0.0": True,
454                        "v7.0.0": True,
455                        "v6.0.5": True,
456                        "v6.4.4": True,
457                        "v6.4.0": True,
458                        "v6.4.1": True,
459                        "v6.2.0": True,
460                        "v6.2.3": True,
461                        "v6.2.5": True,
462                        "v6.2.7": True,
463                        "v6.0.11": True
464                    }
465                },
466                {
467                    "value": "SSLv3",
468                    "revisions": {
469                        "v6.0.0": True,
470                        "v7.0.0": True,
471                        "v6.0.5": True,
472                        "v6.4.4": True,
473                        "v6.4.0": True,
474                        "v6.4.1": True,
475                        "v6.2.0": True,
476                        "v6.2.3": True,
477                        "v6.2.5": True,
478                        "v6.2.7": True,
479                        "v6.0.11": True
480                    }
481                },
482                {
483                    "value": "TLSv1",
484                    "revisions": {
485                        "v6.0.0": True,
486                        "v7.0.0": True,
487                        "v6.0.5": True,
488                        "v6.4.4": True,
489                        "v6.4.0": True,
490                        "v6.4.1": True,
491                        "v6.2.0": True,
492                        "v6.2.3": True,
493                        "v6.2.5": True,
494                        "v6.2.7": True,
495                        "v6.0.11": True
496                    }
497                },
498                {
499                    "value": "TLSv1-1",
500                    "revisions": {
501                        "v6.0.0": True,
502                        "v7.0.0": True,
503                        "v6.0.5": True,
504                        "v6.4.4": True,
505                        "v6.4.0": True,
506                        "v6.4.1": True,
507                        "v6.2.0": True,
508                        "v6.2.3": True,
509                        "v6.2.5": True,
510                        "v6.2.7": True,
511                        "v6.0.11": True
512                    }
513                },
514                {
515                    "value": "TLSv1-2",
516                    "revisions": {
517                        "v6.0.0": True,
518                        "v7.0.0": True,
519                        "v6.0.5": True,
520                        "v6.4.4": True,
521                        "v6.4.0": True,
522                        "v6.4.1": True,
523                        "v6.2.0": True,
524                        "v6.2.3": True,
525                        "v6.2.5": True,
526                        "v6.2.7": True,
527                        "v6.0.11": True
528                    }
529                }
530            ],
531            "revisions": {
532                "v6.0.0": True,
533                "v7.0.0": True,
534                "v6.0.5": True,
535                "v6.4.4": True,
536                "v6.4.0": True,
537                "v6.4.1": True,
538                "v6.2.0": True,
539                "v6.2.3": True,
540                "v6.2.5": True,
541                "v6.2.7": True,
542                "v6.0.11": True
543            }
544        },
545        "validate_server": {
546            "type": "string",
547            "options": [
548                {
549                    "value": "enable",
550                    "revisions": {
551                        "v6.0.0": True,
552                        "v7.0.0": True,
553                        "v6.0.5": True,
554                        "v6.4.4": True,
555                        "v6.4.0": True,
556                        "v6.4.1": True,
557                        "v6.2.0": True,
558                        "v6.2.3": True,
559                        "v6.2.5": True,
560                        "v6.2.7": True,
561                        "v6.0.11": True
562                    }
563                },
564                {
565                    "value": "disable",
566                    "revisions": {
567                        "v6.0.0": True,
568                        "v7.0.0": True,
569                        "v6.0.5": True,
570                        "v6.4.4": True,
571                        "v6.4.0": True,
572                        "v6.4.1": True,
573                        "v6.2.0": True,
574                        "v6.2.3": True,
575                        "v6.2.5": True,
576                        "v6.2.7": True,
577                        "v6.0.11": True
578                    }
579                }
580            ],
581            "revisions": {
582                "v6.0.0": True,
583                "v7.0.0": True,
584                "v6.0.5": True,
585                "v6.4.4": True,
586                "v6.4.0": True,
587                "v6.4.1": True,
588                "v6.2.0": True,
589                "v6.2.3": True,
590                "v6.2.5": True,
591                "v6.2.7": True,
592                "v6.0.11": True
593            }
594        },
595        "interface": {
596            "type": "string",
597            "revisions": {
598                "v7.0.0": True
599            }
600        },
601        "security": {
602            "type": "string",
603            "options": [
604                {
605                    "value": "none",
606                    "revisions": {
607                        "v6.0.0": True,
608                        "v7.0.0": True,
609                        "v6.0.5": True,
610                        "v6.4.4": True,
611                        "v6.4.0": True,
612                        "v6.4.1": True,
613                        "v6.2.0": True,
614                        "v6.2.3": True,
615                        "v6.2.5": True,
616                        "v6.2.7": True,
617                        "v6.0.11": True
618                    }
619                },
620                {
621                    "value": "starttls",
622                    "revisions": {
623                        "v6.0.0": True,
624                        "v7.0.0": True,
625                        "v6.0.5": True,
626                        "v6.4.4": True,
627                        "v6.4.0": True,
628                        "v6.4.1": True,
629                        "v6.2.0": True,
630                        "v6.2.3": True,
631                        "v6.2.5": True,
632                        "v6.2.7": True,
633                        "v6.0.11": True
634                    }
635                },
636                {
637                    "value": "smtps",
638                    "revisions": {
639                        "v6.0.0": True,
640                        "v7.0.0": True,
641                        "v6.0.5": True,
642                        "v6.4.4": True,
643                        "v6.4.0": True,
644                        "v6.4.1": True,
645                        "v6.2.0": True,
646                        "v6.2.3": True,
647                        "v6.2.5": True,
648                        "v6.2.7": True,
649                        "v6.0.11": True
650                    }
651                }
652            ],
653            "revisions": {
654                "v6.0.0": True,
655                "v7.0.0": True,
656                "v6.0.5": True,
657                "v6.4.4": True,
658                "v6.4.0": True,
659                "v6.4.1": True,
660                "v6.2.0": True,
661                "v6.2.3": True,
662                "v6.2.5": True,
663                "v6.2.7": True,
664                "v6.0.11": True
665            }
666        },
667        "password": {
668            "type": "string",
669            "revisions": {
670                "v6.0.0": True,
671                "v7.0.0": True,
672                "v6.0.5": True,
673                "v6.4.4": True,
674                "v6.4.0": True,
675                "v6.4.1": True,
676                "v6.2.0": True,
677                "v6.2.3": True,
678                "v6.2.5": True,
679                "v6.2.7": True,
680                "v6.0.11": True
681            }
682        },
683        "type": {
684            "type": "string",
685            "options": [
686                {
687                    "value": "custom",
688                    "revisions": {
689                        "v6.0.0": True,
690                        "v7.0.0": True,
691                        "v6.0.5": True,
692                        "v6.4.4": True,
693                        "v6.4.0": True,
694                        "v6.4.1": True,
695                        "v6.2.0": True,
696                        "v6.2.3": True,
697                        "v6.2.5": True,
698                        "v6.2.7": True,
699                        "v6.0.11": True
700                    }
701                }
702            ],
703            "revisions": {
704                "v6.0.0": True,
705                "v7.0.0": True,
706                "v6.0.5": True,
707                "v6.4.4": True,
708                "v6.4.0": True,
709                "v6.4.1": True,
710                "v6.2.0": True,
711                "v6.2.3": True,
712                "v6.2.5": True,
713                "v6.2.7": True,
714                "v6.0.11": True
715            }
716        },
717        "port": {
718            "type": "integer",
719            "revisions": {
720                "v6.0.0": True,
721                "v7.0.0": True,
722                "v6.0.5": True,
723                "v6.4.4": True,
724                "v6.4.0": True,
725                "v6.4.1": True,
726                "v6.2.0": True,
727                "v6.2.3": True,
728                "v6.2.5": True,
729                "v6.2.7": True,
730                "v6.0.11": True
731            }
732        },
733        "interface_select_method": {
734            "type": "string",
735            "options": [
736                {
737                    "value": "auto",
738                    "revisions": {
739                        "v7.0.0": True
740                    }
741                },
742                {
743                    "value": "sdwan",
744                    "revisions": {
745                        "v7.0.0": True
746                    }
747                },
748                {
749                    "value": "specify",
750                    "revisions": {
751                        "v7.0.0": True
752                    }
753                }
754            ],
755            "revisions": {
756                "v7.0.0": True
757            }
758        }
759    },
760    "revisions": {
761        "v6.0.0": True,
762        "v7.0.0": True,
763        "v6.0.5": True,
764        "v6.4.4": True,
765        "v6.4.0": True,
766        "v6.4.1": True,
767        "v6.2.0": True,
768        "v6.2.3": True,
769        "v6.2.5": True,
770        "v6.2.7": True,
771        "v6.0.11": True
772    }
773}
774
775
776def main():
777    module_spec = schema_to_module_spec(versioned_schema)
778    mkeyname = None
779    fields = {
780        "access_token": {"required": False, "type": "str", "no_log": True},
781        "enable_log": {"required": False, "type": bool},
782        "vdom": {"required": False, "type": "str", "default": "root"},
783        "system_email_server": {
784            "required": False, "type": "dict", "default": None,
785            "options": {
786            }
787        }
788    }
789    for attribute_name in module_spec['options']:
790        fields["system_email_server"]['options'][attribute_name] = module_spec['options'][attribute_name]
791        if mkeyname and mkeyname == attribute_name:
792            fields["system_email_server"]['options'][attribute_name]['required'] = True
793
794    check_legacy_fortiosapi()
795    module = AnsibleModule(argument_spec=fields,
796                           supports_check_mode=False)
797
798    versions_check_result = None
799    if module._socket_path:
800        connection = Connection(module._socket_path)
801        if 'access_token' in module.params:
802            connection.set_option('access_token', module.params['access_token'])
803
804        if 'enable_log' in module.params:
805            connection.set_option('enable_log', module.params['enable_log'])
806        else:
807            connection.set_option('enable_log', False)
808        fos = FortiOSHandler(connection, module, mkeyname)
809        versions_check_result = check_schema_versioning(fos, versioned_schema, "system_email_server")
810
811        is_error, has_changed, result = fortios_system(module.params, fos)
812
813    else:
814        module.fail_json(**FAIL_SOCKET_MSG)
815
816    if versions_check_result and versions_check_result['matched'] is False:
817        module.warn("Ansible has detected version mismatch between FortOS system and your playbook, see more details by specifying option -vvv")
818
819    if not is_error:
820        if versions_check_result and versions_check_result['matched'] is False:
821            module.exit_json(changed=has_changed, version_check_warning=versions_check_result, meta=result)
822        else:
823            module.exit_json(changed=has_changed, meta=result)
824    else:
825        if versions_check_result and versions_check_result['matched'] is False:
826            module.fail_json(msg="Error in repo", version_check_warning=versions_check_result, meta=result)
827        else:
828            module.fail_json(msg="Error in repo", meta=result)
829
830
831if __name__ == '__main__':
832    main()
833