def make_zeekctl_config_sh(cmdout): ostr = "" for (varname, value) in config.Config.options(dynamic=False): if isinstance(value, bool): # Convert bools to the string "1" or "0" value = "1" if value else "0" else: value = str(value) # In order to prevent shell errors, here we convert plugin # option names to use underscores, and double quotes in the value # are escaped. ostr += '%s="%s"\n' % (varname.replace(".", "_"), value.replace('"', '\\"')) # Rather than just overwriting the file, we first write out a tmp file, # and then rename it to avoid a race condition where a process outside of # zeekctl (such as archive-log) is trying to read the file while it is # being written. cfg_path = os.path.join(config.Config.zeekctlconfigdir, "zeekctl-config.sh") tmp_path = os.path.join(config.Config.zeekctlconfigdir, ".zeekctl-config.sh.tmp") try: with open(tmp_path, "w") as out: out.write(ostr) except IOError as e: cmdout.error("failed to write file: %s" % e) return False try: os.rename(tmp_path, cfg_path) except OSError as e: cmdout.error("failed to rename file %s: %s" % (tmp_path, e)) return False symlink = os.path.join(config.Config.scriptsdir, "zeekctl-config.sh") # check if the symlink needs to be updated try: update_link = not os.path.islink( symlink) or os.readlink(symlink) != cfg_path except OSError as e: cmdout.error("failed to read symlink: %s" % e) return False if update_link: # attempt to update the symlink try: util.force_symlink(cfg_path, symlink) except OSError as e: cmdout.error("failed to update symlink '%s' to point to '%s': %s" % (symlink, cfg_path, e.strerror)) return False return True
def install(self, local_only): results = cmdresult.CmdResult() try: self.config.record_zeek_version() except config.ConfigurationError as err: self.ui.error("%s" % err) results.ok = False return results manager = self.config.manager() # Delete previously installed policy files to not mix things up. policies = [self.config.policydirsiteinstall, self.config.policydirsiteinstallauto] for dirpath in policies: if os.path.isdir(dirpath): self.ui.info("removing old policies in %s ..." % dirpath) try: shutil.rmtree(dirpath) except OSError as err: self.ui.error("failed to remove directory %s: %s" % (dirpath, err)) results.ok = False return results self.ui.info("creating policy directories ...") for dirpath in policies: try: os.makedirs(dirpath) except OSError as err: self.ui.error("failed to create directory: %s" % err) results.ok = False return results # Install local site policy. if self.config.sitepolicypath: self.ui.info("installing site policies ...") dst = self.config.policydirsiteinstall for dir in self.config.sitepolicypath.split(":"): dirpath = self.config.subst(dir) for pathname in glob.glob(os.path.join(dirpath, "*")): if not execute.install(pathname, dst, self.ui): results.ok = False return results if not install.make_layout(self.config.policydirsiteinstallauto, self.ui): results.ok = False return results self.ui.info("generating local-networks.zeek ...") if not install.make_local_networks(self.config.policydirsiteinstallauto, self.ui): results.ok = False return results self.ui.info("generating zeekctl-config.zeek ...") if not install.make_zeekctl_config_policy(self.config.policydirsiteinstallauto, self.ui, self.pluginregistry): results.ok = False return results loggers = self.config.loggers() if loggers: # Just use the first logger that is defined. node_cwd = loggers[0].cwd() else: node_cwd = manager.cwd() current = self.config.subst(os.path.join(self.config.logdir, "current")) try: util.force_symlink(node_cwd, current) except (IOError, OSError) as err: results.ok = False self.ui.error("failed to update symlink '%s': %s" % (current, err)) return results self.ui.info("generating zeekctl-config.sh ...") if not install.make_zeekctl_config_sh(self.ui): results.ok = False return results if local_only: return results # Make sure we install each remote host only once. nodes = self.config.hosts(exclude_local=True) # If there are no remote hosts, then we're done. if not nodes: # Save current configuration state. self.config.update_cfg_hash() return results # Sync to clients. self.ui.info("updating nodes ...") dirs = [] if not self.config.havenfs: # Non-NFS, need to explicitly synchronize. syncs = install.get_syncs() else: # NFS. We only need to take care of the spool/log directories. # We need this only on the manager. dirs.append((manager, self.config.logdir)) syncs = install.get_nfssyncs() syncs = [(dir, mirror) for (dir, mirror, optional) in syncs if not optional or os.path.exists(self.config.subst(dir))] createdirs = [self.config.subst(dir) for (dir, mirror) in syncs if not mirror] for n in nodes: for dir in createdirs: dirs.append((n, dir)) for (node, success, output) in self.executor.mkdirs(dirs): if not success: self.ui.error("cannot create a directory on node %s" % node.name) if output: self.ui.error(output) results.ok = False return results paths = [self.config.subst(dir) for (dir, mirror) in syncs if mirror] if not execute.sync(nodes, paths, self.ui): results.ok = False return results # Save current configuration state. self.config.update_cfg_hash() return results