def test_code_injection2(self):
        self.setup()
        self.addCleanup(self.cleanup)
        # failure cases
        out_file = self.get_random_filename()
        exit_code = ext_utils.run_command_and_write_stdout_to_file(
            "echo hello; echo world", out_file)
        self.assertNotEqual(0, exit_code, "exit code != 0")

        out_file = self.get_random_filename()
        exit_code = ext_utils.run_command_and_write_stdout_to_file(
            ["echo hello; echo world"], out_file)
        self.assertNotEqual(0, exit_code, "exit code != 0")

        # success case
        out_file = self.get_random_filename()
        exit_code = ext_utils.run_command_and_write_stdout_to_file(
            ["echo", "hello", ";", "echo", "world"], out_file)
        self.assertEqual(0, exit_code, "exit code == 0")
        file_contents = ext_utils.get_file_contents(out_file)
        self.assertEqual("hello ; echo world\n", file_contents,
                         "unexpected output")

        out_file = self.get_random_filename()
        exit_code = ext_utils.run_command_and_write_stdout_to_file(
            ["echo", "hello", "world"], out_file)
        self.assertEqual(0, exit_code, "exit code == 0")
        file_contents = ext_utils.get_file_contents(out_file)
        self.assertEqual("hello world\n", file_contents, "unexpected output")
Exemplo n.º 2
0
 def create_account(self, user, password, expiration, thumbprint):
     """
     Create a user account, with 'user', 'password', 'expiration', ssh keys
     and sudo permissions.
     Returns None if successful, error string on failure.
     """
     userentry = None
     try:
         userentry = pwd.getpwnam(user)
     except (EnvironmentError, KeyError):
         pass
     uidmin = None
     try:
         uidmin = int(ext_utils.get_line_starting_with("UID_MIN", "/etc/login.defs").split()[1])
     except (ValueError, KeyError, AttributeError, EnvironmentError):
         pass
     if uidmin is None:
         uidmin = 100
     if userentry is not None and userentry[2] < uidmin and userentry[2] != self.CORE_UID:
         logger.error(
             "CreateAccount: " + user + " is a system user. Will not set password.")
         return "Failed to set password for system user: "******" (0x06)."
     if userentry is None:
         command = ['useradd', '--create-home',  '--password', '*',  user]
         if expiration is not None:
             command += ['--expiredate', expiration.split('.')[0]]
         if ext_utils.run(command):
             logger.error("Failed to create user account: " + user)
             return "Failed to create user account: " + user + " (0x07)."
     else:
         logger.log("CreateAccount: " + user + " already exists. Will update password.")
     if password is not None:
         self.change_password(user, password)
     try:
         if password is None:
             ext_utils.set_file_contents("/etc/sudoers.d/waagent", user + " ALL = (ALL) NOPASSWD: ALL\n")
         else:
             ext_utils.set_file_contents("/etc/sudoers.d/waagent", user + " ALL = (ALL) ALL\n")
         os.chmod("/etc/sudoers.d/waagent", 0o440)
     except EnvironmentError:
         logger.error("CreateAccount: Failed to configure sudo access for user.")
         return "Failed to configure sudo privileges (0x08)."
     home = self.get_home()
     if thumbprint is not None:
         ssh_dir = home + "/" + user + "/.ssh"
         ext_utils.create_dir(ssh_dir, user, 0o700)
         pub = ssh_dir + "/id_rsa.pub"
         prv = ssh_dir + "/id_rsa"
         ext_utils.run_command_and_write_stdout_to_file(['ssh-keygen', '-y', '-f', thumbprint + '.prv'], pub)
         ext_utils.set_file_contents(prv, ext_utils.get_file_contents(thumbprint + ".prv"))
         for f in [pub, prv]:
             os.chmod(f, 0o600)
             ext_utils.change_owner(f, user)
         ext_utils.set_file_contents(ssh_dir + "/authorized_keys", ext_utils.get_file_contents(pub))
         ext_utils.change_owner(ssh_dir + "/authorized_keys", user)
     logger.log("Created user account: " + user)
     return None
    def try_parse_context(self):
        self._context = HandlerContext(self._short_name)
        handler_env = None
        config = None
        ctxt = None
        code = 0
        # get the HandlerEnvironment.json. According to the extension handler spec, it is always in the ./ directory
        self.log('cwd is ' + os.path.realpath(os.path.curdir))
        handler_env_file = './HandlerEnvironment.json'
        if not os.path.isfile(handler_env_file):
            self.error("Unable to locate " + handler_env_file)
            return None
        ctxt = ext_utils.get_file_contents(handler_env_file)
        if ctxt == None:
            self.error("Unable to read " + handler_env_file)
        try:
            handler_env = json.loads(ctxt)
        except:
            pass
        if handler_env == None:
            self.log("JSON error processing " + handler_env_file)
            return None
        if type(handler_env) == list:
            handler_env = handler_env[0]

        self._context._name = handler_env['name']
        self._context._version = str(handler_env['version'])
        self._context._config_dir = handler_env['handlerEnvironment']['configFolder']
        self._context._log_dir = handler_env['handlerEnvironment']['logFolder']

        self._context._log_file = os.path.join(handler_env['handlerEnvironment']['logFolder'], self._logFileName)
        self._change_log_file()
        self._context._status_dir = handler_env['handlerEnvironment']['statusFolder']
        self._context._heartbeat_file = handler_env['handlerEnvironment']['heartbeatFile']
        self._context._seq_no = self._get_current_seq_no(self._context._config_dir)
        if self._context._seq_no < 0:
            self.error("Unable to locate a .settings file!")
            return None
        self._context._seq_no = str(self._context._seq_no)
        self.log('sequence number is ' + self._context._seq_no)
        self._context._status_file = os.path.join(self._context._status_dir, self._context._seq_no + '.status')
        self._context._settings_file = os.path.join(self._context._config_dir, self._context._seq_no + '.settings')
        self.log("setting file path is" + self._context._settings_file)
        ctxt = None
        ctxt = ext_utils.get_file_contents(self._context._settings_file)
        if ctxt == None:
            error_msg = 'Unable to read ' + self._context._settings_file + '. '
            self.error(error_msg)
            return None

        self.log("JSON config: " + HandlerUtility.redact_protected_settings(ctxt))
        self._context._config = self._parse_config(ctxt)
        return self._context
Exemplo n.º 4
0
def get_my_distro(config):
    if 'FreeBSD' in platform.system():
        return FreeBSDDistro(config)

    if os.path.isfile(constants.os_release):
        os_name = ext_utils.get_line_starting_with("NAME", constants.os_release)
    elif os.path.isfile(constants.system_release):
        os_name = ext_utils.get_file_contents(constants.system_release)
    else:
        return GenericDistro(config)
    if os_name is not None:
        if re.search("fedora", os_name, re.IGNORECASE):
            # Fedora
            return FedoraDistro(config)
        if re.search("red\s?hat", os_name, re.IGNORECASE):
            # Red Hat
            return RedhatDistro(config)
        if re.search("centos", os_name, re.IGNORECASE):
            # CentOS
            return CentOSDistro(config)
        if re.search("coreos", os_name, re.IGNORECASE):
            # CoreOs
            return CoreOSDistro(config)
        if re.search("freebsd", os_name, re.IGNORECASE):
            # FreeBSD
            return FreeBSDDistro(config)
    return GenericDistro(config)
    def _get_most_recent_seq(self):
        if (os.path.isfile('mrseq')):
            seq = ext_utils.get_file_contents('mrseq')
            if (seq):
                return int(seq)

        return -1
Exemplo n.º 6
0
def _get_other_sudoers(user_name):
    sudoers_file = '/etc/sudoers.d/waagent'
    if not os.path.isfile(sudoers_file):
        return None
    sudoers = ext_utils.get_file_contents(sudoers_file).split("\n")
    pattern = '^{0}\s'.format(user_name)
    sudoers = list(filter(lambda x: re.match(pattern, x) is None, sudoers))
    return sudoers
Exemplo n.º 7
0
def _reset_sshd_config(sshd_file_path):
    ssh_default_config_filename = _get_default_ssh_config_filename()
    ssh_default_config_file_path = os.path.join(os.getcwd(), 'resources',
                                                ssh_default_config_filename)
    if not (os.path.exists(ssh_default_config_file_path)):
        ssh_default_config_file_path = os.path.join(os.getcwd(), 'resources',
                                                    'default')

    # handle CoreOS differently
    if isinstance(MyDistro, dist_utils.CoreOSDistro):
        # Parse sshd port from ssh_default_config_file_path
        sshd_port = 22
        regex = re.compile(r"^Port\s+(\d+)", re.VERBOSE)
        with open(ssh_default_config_file_path) as f:
            for line in f:
                match = regex.match(line)
                if match:
                    sshd_port = match.group(1)
                    break

        # Prepare cloud init config for coreos-cloudinit
        f = tempfile.NamedTemporaryFile(delete=False)
        f.close()
        cfg_tempfile = f.name
        cfg_content = "#cloud-config\n\n"

        # Overwrite /etc/ssh/sshd_config
        cfg_content += "write_files:\n"
        cfg_content += "  - path: {0}\n".format(sshd_file_path)
        cfg_content += "    permissions: 0600\n"
        cfg_content += "    owner: root:root\n"
        cfg_content += "    content: |\n"
        for line in ext_utils.get_file_contents(
                ssh_default_config_file_path).split('\n'):
            cfg_content += "      {0}\n".format(line)

        # Change the sshd port in /etc/systemd/system/sshd.socket
        cfg_content += "\ncoreos:\n"
        cfg_content += "  units:\n"
        cfg_content += "  - name: sshd.socket\n"
        cfg_content += "    command: restart\n"
        cfg_content += "    content: |\n"
        cfg_content += "      [Socket]\n"
        cfg_content += "      ListenStream={0}\n".format(sshd_port)
        cfg_content += "      Accept=yes\n"

        ext_utils.set_file_contents(cfg_tempfile, cfg_content)

        ext_utils.run(['coreos-cloudinit', '-from-file', cfg_tempfile],
                      chk_err=False)
        os.remove(cfg_tempfile)
    else:
        shutil.copyfile(ssh_default_config_file_path, sshd_file_path)
        MyDistro.restart_ssh_service()
Exemplo n.º 8
0
def _forcibly_reset_chap(hutil):
    name = "ChallengeResponseAuthentication"
    config = ext_utils.get_file_contents(SshdConfigPath).split("\n")
    for i in range(0, len(config)):
        if config[i].startswith(name) and "no" in config[i].lower():
            ext_utils.add_extension_event(name=hutil.get_name(), op="sshd", is_success=True,
                                          message="ChallengeResponseAuthentication no")
            return

    ext_utils.add_extension_event(name=hutil.get_name(), op="sshd", is_success=True,
                                  message="ChallengeResponseAuthentication yes")
    _backup_sshd_config(SshdConfigPath)
    _set_sshd_config(config, name, "no")
    ext_utils.replace_file_with_contents_atomic(SshdConfigPath, "\n".join(config))
    MyDistro.restart_ssh_service()
Exemplo n.º 9
0
 def __init__(self, wala_config_file):
     self.values = dict()
     if not os.path.isfile(wala_config_file):
         raise ValueError("Missing configuration in {0}".format(wala_config_file))
     try:
         for line in ext_utils.get_file_contents(wala_config_file).split('\n'):
             if not line.startswith("#") and "=" in line:
                 parts = line.split()[0].split('=')
                 value = parts[1].strip("\" ")
                 if value != "None":
                     self.values[parts[0]] = value
                 else:
                     self.values[parts[0]] = None
     # when get_file_contents returns none
     except AttributeError:
         logger.error("Unable to parse {0}".format(wala_config_file))
         raise
     return
Exemplo n.º 10
0
def _get_default_ssh_config_filename():
    if os.path.isfile(constants.os_release):
        os_name = ext_utils.get_line_starting_with("NAME", constants.os_release)
    elif os.path.isfile(constants.system_release):
        os_name = ext_utils.get_file_contents(constants.system_release)
    else:
        return "default"
    if os_name is not None:
        # the default ssh config files are present in
        # /var/lib/waagent/Microsoft.OSTCExtensions.VMAccessForLinux-<version>/resources/
        if re.search("centos", os_name, re.IGNORECASE):
            return "centos_default"
        if re.search("debian", os_name, re.IGNORECASE):
            return "debian_default"
        if re.search("fedora", os_name, re.IGNORECASE):
            return "fedora_default"
        if re.search("red\s?hat", os_name, re.IGNORECASE):
            return "redhat_default"
        if re.search("suse", os_name, re.IGNORECASE):
            return "SuSE_default"
        if re.search("ubuntu", os_name, re.IGNORECASE):
            return "ubuntu_default"
        return "default"
Exemplo n.º 11
0
 def scrub_settings_file(self):
     content = ext_utils.get_file_contents(self._context._settings_file)
     redacted = HandlerUtility.redact_protected_settings(content)
     ext_utils.set_file_contents(self._context._settings_file, redacted)
 def test_ovf_env_parse_minimalxml(self):
     current_dir = path.dirname(path.abspath(__file__))
     ovf_xml = ext_utils.get_file_contents(
         path.join(current_dir, 'ovf-env-empty.xml'))
     ovf_env = ovf_utils.OvfEnv.parse(ovf_xml, config)
     self.assertIsNone(ovf_env, "ovf_env should be null")
Exemplo n.º 13
0
def _allow_password_auth():
    config = ext_utils.get_file_contents(SshdConfigPath).split("\n")
    _set_sshd_config(config, "PasswordAuthentication", "yes")
    ext_utils.replace_file_with_contents_atomic(SshdConfigPath,
                                                "\n".join(config))
Exemplo n.º 14
0
def _set_user_account_pub_key(protect_settings, hutil):
    ovf_xml = None
    ovf_env = None
    try:
        ovf_xml = ext_utils.get_file_contents('/var/lib/waagent/ovf-env.xml')
        ovf_env = ovf_utils.OvfEnv.parse(ovf_xml, Configuration)
    except (EnvironmentError, ValueError, KeyError, AttributeError):
        pass
    if ovf_xml is None or ovf_env is None:
        # default ovf_env with empty data
        ovf_env = ovf_utils.OvfEnv()
        logger.log("could not load ovf-env.xml")

    # user name must be provided if set ssh key or password
    if not protect_settings or 'username' not in protect_settings:
        return

    user_name = protect_settings['username']
    user_pass = protect_settings.get('password')
    cert_txt = protect_settings.get('ssh_key')
    expiration = protect_settings.get('expiration')
    no_convert = False
    if not user_pass and not cert_txt and not ovf_env.SshPublicKeys:
        raise Exception("No password or ssh_key is specified.")

    if user_pass is not None and len(user_pass) == 0:
        user_pass = None
        hutil.log("empty passwords are not allowed, ignoring password reset")

    # Reset user account and password, password could be empty
    sudoers = _get_other_sudoers(user_name)
    error_string = MyDistro.create_account(user_name, user_pass, expiration,
                                           None)
    _save_other_sudoers(sudoers)

    if error_string is not None:
        err_msg = "Failed to create the account or set the password"
        ext_utils.add_extension_event(name=hutil.get_name(),
                                      op=constants.WALAEventOperation.Enable,
                                      is_success=False,
                                      message="(02101)" + err_msg)
        raise Exception(err_msg + " with " + error_string)
    hutil.log("Succeeded in creating the account or setting the password.")

    # Allow password authentication if user_pass is provided
    if user_pass is not None:
        ext_utils.add_extension_event(name=hutil.get_name(),
                                      op="scenario",
                                      is_success=True,
                                      message="create-user-with-password")
        _allow_password_auth()

    # Reset ssh key with the new public key passed in or reuse old public key.
    if cert_txt:
        if cert_txt and cert_txt.strip().lower().startswith("ssh-rsa"):
            no_convert = True
        try:
            pub_path = os.path.join('/home/', user_name, '.ssh',
                                    'authorized_keys')
            ovf_env.UserName = user_name
            if no_convert:
                if cert_txt:
                    pub_path = ovf_env.prepare_dir(pub_path, MyDistro)
                    final_cert_txt = cert_txt
                    if not cert_txt.endswith("\n"):
                        final_cert_txt = final_cert_txt + "\n"
                    ext_utils.append_file_contents(pub_path, final_cert_txt)
                    MyDistro.set_se_linux_context(
                        pub_path, 'unconfined_u:object_r:ssh_home_t:s0')
                    ext_utils.change_owner(pub_path, user_name)
                    ext_utils.add_extension_event(name=hutil.get_name(),
                                                  op="scenario",
                                                  is_success=True,
                                                  message="create-user")
                    hutil.log("Succeeded in resetting ssh_key.")
                else:
                    err_msg = "Failed to reset ssh key because the cert content is empty."
                    ext_utils.add_extension_event(
                        name=hutil.get_name(),
                        op=constants.WALAEventOperation.Enable,
                        is_success=False,
                        message="(02100)" + err_msg)
            else:
                # do the certificate conversion
                # we support PKCS8 certificates besides ssh-rsa public keys
                _save_cert_str_as_file(cert_txt, 'temp.crt')
                pub_path = ovf_env.prepare_dir(pub_path, MyDistro)
                retcode = ext_utils.run_command_and_write_stdout_to_file([
                    constants.Openssl, 'x509', '-in', 'temp.crt', '-noout',
                    '-pubkey'
                ], "temp.pub")
                if retcode > 0:
                    raise Exception("Failed to generate public key file.")

                MyDistro.ssh_deploy_public_key('temp.pub', pub_path)
                os.remove('temp.pub')
                os.remove('temp.crt')
                ext_utils.add_extension_event(name=hutil.get_name(),
                                              op="scenario",
                                              is_success=True,
                                              message="create-user")
                hutil.log("Succeeded in resetting ssh_key.")
        except Exception as e:
            hutil.log(str(e))
            ext_utils.add_extension_event(
                name=hutil.get_name(),
                op=constants.WALAEventOperation.Enable,
                is_success=False,
                message="(02100)Failed to reset ssh key.")
            raise e
 def test_encode(self):
     contents = eu.get_file_contents('mock_sshd_config')
     encoded_contents = eu.encode_for_writing_to_file(contents)
     known_non_ascii_character = b"%c" % encoded_contents[2353]
     self.assertEqual(known_non_ascii_character, b'\x9d')