Esempio n. 1
0
    def get_version(self):  # pylint: disable=no-self-use
        """Return version of Apache Server.

        Version is returned as tuple. (ie. 2.4.7 = (2, 4, 7))

        :returns: version
        :rtype: tuple

        :raises errors.LetsEncryptConfiguratorError:
            Unable to find Apache version

        """
        try:
            proc = subprocess.Popen(
                [self.config.apache_ctl, '-v'],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE)
            text = proc.communicate()[0]
        except (OSError, ValueError):
            raise errors.LetsEncryptConfiguratorError(
                "Unable to run %s -v" % self.config.apache_ctl)

        regex = re.compile(r"Apache/([0-9\.]*)", re.IGNORECASE)
        matches = regex.findall(text)

        if len(matches) != 1:
            raise errors.LetsEncryptConfiguratorError(
                "Unable to find Apache version")

        return tuple([int(i) for i in matches[0].split('.')])
Esempio n. 2
0
    def get_version(self):
        """Return version of Nginx Server.

        Version is returned as tuple. (ie. 2.4.7 = (2, 4, 7))

        :returns: version
        :rtype: tuple

        :raises errors.LetsEncryptConfiguratorError:
            Unable to find Nginx version or version is unsupported

        """
        try:
            proc = subprocess.Popen(
                [self.config.nginx_ctl, "-V"],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE)
            text = proc.communicate()[1]  # nginx prints output to stderr
        except (OSError, ValueError):
            raise errors.LetsEncryptConfiguratorError(
                "Unable to run %s -V" % self.config.nginx_ctl)

        version_regex = re.compile(r"nginx/([0-9\.]*)", re.IGNORECASE)
        version_matches = version_regex.findall(text)

        sni_regex = re.compile(r"TLS SNI support enabled", re.IGNORECASE)
        sni_matches = sni_regex.findall(text)

        ssl_regex = re.compile(r" --with-http_ssl_module")
        ssl_matches = ssl_regex.findall(text)

        if not version_matches:
            raise errors.LetsEncryptConfiguratorError(
                "Unable to find Nginx version")
        if not ssl_matches:
            raise errors.LetsEncryptConfiguratorError(
                "Nginx build is missing SSL module (--with-http_ssl_module).")
        if not sni_matches:
            raise errors.LetsEncryptConfiguratorError(
                "Nginx build doesn't support SNI")

        nginx_version = tuple([int(i) for i in version_matches[0].split(".")])

        # nginx < 0.8.21 doesn't use default_server
        if nginx_version < (0, 8, 21):
            raise errors.LetsEncryptConfiguratorError(
                "Nginx version must be 0.8.21+")

        return nginx_version
Esempio n. 3
0
def mod_loaded(module, apache_ctl):
    """Checks to see if mod_ssl is loaded

    Uses ``apache_ctl`` to get loaded module list. This also effectively
    serves as a config_test.

    :param str apache_ctl: Path to apache2ctl binary.

    :returns: If ssl_module is included and active in Apache
    :rtype: bool

    """
    try:
        proc = subprocess.Popen(
            [apache_ctl, '-M'],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE)
        stdout, stderr = proc.communicate()

    except (OSError, ValueError):
        logging.error(
            "Error accessing %s for loaded modules!", apache_ctl)
        raise errors.LetsEncryptConfiguratorError(
            "Error accessing loaded modules")
    # Small errors that do not impede
    if proc.returncode != 0:
        logging.warn("Error in checking loaded module list: %s", stderr)
        raise errors.LetsEncryptMisconfigurationError(
            "Apache is unable to check whether or not the module is "
            "loaded because Apache is misconfigured.")

    if module in stdout:
        return True
    return False
    def _enable_redirect(self, ssl_vhost, unused_options):
        """Redirect all equivalent HTTP traffic to ssl_vhost.

        .. todo:: This enhancement should be rewritten and will
           unfortunately require lots of debugging by hand.

        Adds Redirect directive to the port 80 equivalent of ssl_vhost
        First the function attempts to find the vhost with equivalent
        ip addresses that serves on non-ssl ports
        The function then adds the directive

        .. note:: This function saves the configuration

        :param ssl_vhost: Destination of traffic, an ssl enabled vhost
        :type ssl_vhost:
            :class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`

        :param unused_options: Not currently used
        :type unused_options: Not Available

        :returns: Success, general_vhost (HTTP vhost)
        :rtype: (bool,
            :class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`)

        """
        if not mod_loaded("rewrite_module", self.config.apache_ctl):
            enable_mod("rewrite", self.config.apache_init_script,
                       self.config.apache_enmod)

        general_v = self._general_vhost(ssl_vhost)
        if general_v is None:
            # Add virtual_server with redirect
            logging.debug(
                "Did not find http version of ssl virtual host... creating")
            return self._create_redirect_vhost(ssl_vhost)
        else:
            # Check if redirection already exists
            exists, code = self._existing_redirect(general_v)
            if exists:
                if code == 0:
                    logging.debug("Redirect already added")
                    logging.info(
                        "Configuration is already redirecting traffic to HTTPS"
                    )
                    return
                else:
                    logging.info("Unknown redirect exists for this vhost")
                    raise errors.LetsEncryptConfiguratorError(
                        "Unknown redirect already exists "
                        "in {}".format(general_v.filep))
            # Add directives to server
            self.parser.add_dir(general_v.path, "RewriteEngine", "On")
            self.parser.add_dir(general_v.path, "RewriteRule",
                                constants.APACHE_REWRITE_HTTPS_ARGS)
            self.save_notes += ("Redirecting host in %s to ssl vhost in %s\n" %
                                (general_v.filep, ssl_vhost.filep))
            self.save()

            logging.info("Redirecting vhost in %s to ssl vhost in %s",
                         general_v.filep, ssl_vhost.filep)
Esempio n. 5
0
    def enhance(self, domain, enhancement, options=None):
        """Enhance configuration.

        :param str domain: domain to enhance
        :param str enhancement: enhancement type defined in
            :const:`~letsencrypt.client.constants.ENHANCEMENTS`
        :param options: options for the enhancement
            See :const:`~letsencrypt.client.constants.ENHANCEMENTS`
            documentation for appropriate parameter.

        """
        try:
            return self._enhance_func[enhancement](self.choose_vhost(domain),
                                                   options)
        except (KeyError, ValueError):
            raise errors.LetsEncryptConfiguratorError(
                "Unsupported enhancement: {0}".format(enhancement))
        except errors.LetsEncryptConfiguratorError:
            logging.warn("Failed %s for %s", enhancement, domain)
Esempio n. 6
0
    def _create_redirect_vhost(self, ssl_vhost):
        """Creates an http_vhost specifically to redirect for the ssl_vhost.

        :param ssl_vhost: ssl vhost
        :type ssl_vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`

        :returns: Success, vhost
        :rtype: (bool, :class:`letsencrypt.client.apache.obj.VirtualHost`)

        """
        # Consider changing this to a dictionary check
        # Make sure adding the vhost will be safe
        conflict, host_or_addrs = self._conflicting_host(ssl_vhost)
        if conflict:
            raise errors.LetsEncryptConfiguratorError(
                "Unable to create a redirection vhost "
                "- {}".format(host_or_addrs))

        redirect_addrs = host_or_addrs

        # get servernames and serveraliases
        serveralias = ""
        servername = ""
        size_n = len(ssl_vhost.names)
        if size_n > 0:
            servername = "ServerName " + ssl_vhost.names[0]
            if size_n > 1:
                serveralias = " ".join(ssl_vhost.names[1:size_n])
                serveralias = "ServerAlias " + serveralias
        redirect_file = ("<VirtualHost" + redirect_addrs + ">\n"
                         "%s \n"
                         "%s \n"
                         "ServerSignature Off\n"
                         "\n"
                         "RewriteEngine On\n"
                         "RewriteRule %s\n"
                         "\n"
                         "ErrorLog /var/log/apache2/redirect.error.log\n"
                         "LogLevel warn\n"
                         "</VirtualHost>\n"
                         % (servername, serveralias,
                            " ".join(constants.APACHE_REWRITE_HTTPS_ARGS)))

        # Write out the file
        # This is the default name
        redirect_filename = "le-redirect.conf"

        # See if a more appropriate name can be applied
        if len(ssl_vhost.names) > 0:
            # Sanity check...
            # make sure servername doesn't exceed filename length restriction
            if ssl_vhost.names[0] < (255-23):
                redirect_filename = "le-redirect-%s.conf" % ssl_vhost.names[0]

        redirect_filepath = os.path.join(
            self.parser.root, 'sites-available', redirect_filename)

        # Register the new file that will be created
        # Note: always register the creation before writing to ensure file will
        # be removed in case of unexpected program exit
        self.reverter.register_file_creation(False, redirect_filepath)

        # Write out file
        with open(redirect_filepath, 'w') as redirect_fd:
            redirect_fd.write(redirect_file)
        logging.info("Created redirect file: %s", redirect_filename)

        self.aug.load()
        # Make a new vhost data structure and add it to the lists
        new_vhost = self._create_vhost(parser.get_aug_path(redirect_filepath))
        self.vhosts.append(new_vhost)

        # Finally create documentation for the change
        self.save_notes += ('Created a port 80 vhost, %s, for redirection to '
                            'ssl vhost %s\n' %
                            (new_vhost.filep, ssl_vhost.filep))