def CleanDirectory(self, directory): logging.info("Clearing directory %s", directory) try: shutil.rmtree(directory) except OSError: pass utils.EnsureDirExists(directory)
def CreateInstallDirs(self): utils.EnsureDirExists(self.build_dir) utils.EnsureDirExists(self.script_dir) utils.EnsureDirExists(self.pkg_root) if self.fleetspeak_enabled: utils.EnsureDirExists(self.pkg_fleetspeak_service_dir) else: utils.EnsureDirExists( os.path.join(self.pkg_root, "Library/LaunchDaemons")) utils.EnsureDirExists(os.path.join(self.pkg_root, "usr/local/lib/")) utils.EnsureDirExists(self.pkgbuild_out_dir) utils.EnsureDirExists(self.prodbuild_out_dir)
def MakeDeployableBinary(self, template_path, output_path): """This will add the config to the client template.""" context = self.context + ["Client Context"] utils.EnsureDirExists(os.path.dirname(output_path)) client_config_data = self.GetClientConfig(context) shutil.copyfile(template_path, output_path) zip_file = zipfile.ZipFile(output_path, mode="a") zip_info = zipfile.ZipInfo(filename="config.yaml") zip_file.writestr(zip_info, client_config_data) zip_file.close() return output_path
def CopyFiles(self): """This sets up the template directory.""" # Copy the nanny binary. shutil.copy( config_lib.Resource().Filter( "install_data/debian/dpkg_client/nanny.sh.in"), self.output_dir) dpkg_dir = config.CONFIG.Get("PyInstaller.dpkg_root", context=self.context) # Copy files needed for dpkg-buildpackage. shutil.copytree( config_lib.Resource().Filter( "install_data/debian/dpkg_client/debian"), os.path.join(dpkg_dir, "debian/debian.in")) # Copy upstart files outdir = os.path.join(dpkg_dir, "debian/upstart.in") utils.EnsureDirExists(outdir) shutil.copy( config_lib.Resource().Filter( "install_data/debian/dpkg_client/upstart/grr-client.conf"), outdir) # Copy init files outdir = os.path.join(dpkg_dir, "debian/initd.in") utils.EnsureDirExists(outdir) shutil.copy( config_lib.Resource().Filter( "install_data/debian/dpkg_client/initd/grr-client"), outdir) # Copy systemd unit file outdir = os.path.join(dpkg_dir, "debian/systemd.in") utils.EnsureDirExists(outdir) shutil.copy( config_lib.Resource().Filter( "install_data/systemd/client/grr-client.service"), outdir)
def GenerateDirectory(self, input_dir=None, output_dir=None, replacements=None): input_dir = utils.NormalizePath(input_dir) output_dir = utils.NormalizePath(output_dir) replacements = replacements or [] for (root, _, files) in os.walk(input_dir): for filename in files: in_file = utils.JoinPath(root, filename) out_file = in_file.replace(input_dir, output_dir) for (s, replacement) in replacements: out_file = out_file.replace(s, replacement) utils.EnsureDirExists(os.path.dirname(out_file)) self.GenerateFile(in_file, out_file)
def MakeExecutableTemplate(self, output_file=None): """Create the executable template. Args: output_file: string filename where we will write the template. The client is build in two phases. First an executable template is created with the client binaries contained inside a zip file. Then the installation package is created by appending the SFX extractor to this template and writing a config file into the zip file. This technique allows the client build to be carried out once on the supported platform (e.g. windows with MSVS), but the deployable installer can be build on any platform which supports python. Subclasses for each OS do the actual work, we just make sure the output directory is set up correctly here. """ self.template_file = output_file or config.CONFIG.Get( "ClientBuilder.template_path", context=self.context) utils.EnsureDirExists(os.path.dirname(self.template_file))
def RenamePkgToTemplate(self, output_file): print "Copying output to templates location: %s -> %s" % ( self.prodbuild_out_binary, output_file) utils.EnsureDirExists(os.path.dirname(output_file)) shutil.copyfile(self.prodbuild_out_binary, output_file)
def MakeDeployableBinary(self, template_path, output_path): """This will add the config to the client template and create a .rpm.""" rpmbuild_binary = "/usr/bin/rpmbuild" if not os.path.exists(rpmbuild_binary): logging.error("rpmbuild not found, unable to repack client.") return with utils.TempDirectory() as tmp_dir: template_dir = os.path.join(tmp_dir, "dist") utils.EnsureDirExists(template_dir) zf = zipfile.ZipFile(template_path) for name in zf.namelist(): dirname = os.path.dirname(name) utils.EnsureDirExists(os.path.join(template_dir, dirname)) with open(os.path.join(template_dir, name), "wb") as fd: fd.write(zf.read(name)) # Set up a RPM building environment. rpm_root_dir = os.path.join(tmp_dir, "rpmbuild") rpm_build_dir = os.path.join(rpm_root_dir, "BUILD") utils.EnsureDirExists(rpm_build_dir) rpm_buildroot_dir = os.path.join(rpm_root_dir, "BUILDROOT") utils.EnsureDirExists(rpm_buildroot_dir) rpm_rpms_dir = os.path.join(rpm_root_dir, "RPMS") utils.EnsureDirExists(rpm_rpms_dir) rpm_specs_dir = os.path.join(rpm_root_dir, "SPECS") utils.EnsureDirExists(rpm_specs_dir) template_binary_dir = os.path.join(tmp_dir, "dist/rpmbuild/grr-client") target_binary_dir = "%s%s" % (rpm_build_dir, config.CONFIG.Get( "ClientBuilder.target_dir", context=self.context)) utils.EnsureDirExists(os.path.dirname(target_binary_dir)) try: shutil.rmtree(target_binary_dir) except OSError: pass shutil.move(template_binary_dir, target_binary_dir) client_name = config.CONFIG.Get("Client.name", context=self.context) client_binary_name = config.CONFIG.Get("Client.binary_name", context=self.context) if client_binary_name != "grr-client": shutil.move( os.path.join(target_binary_dir, "grr-client"), os.path.join(target_binary_dir, client_binary_name)) # Generate spec spec_filename = os.path.join(rpm_specs_dir, "%s.spec" % client_name) self.GenerateFile( os.path.join(tmp_dir, "dist/rpmbuild/grr.spec.in"), spec_filename) initd_target_filename = os.path.join(rpm_build_dir, "etc/init.d", client_name) # Generate init.d utils.EnsureDirExists(os.path.dirname(initd_target_filename)) self.GenerateFile( os.path.join(tmp_dir, "dist/rpmbuild/grr-client.initd.in"), initd_target_filename) # Generate systemd unit if config.CONFIG["Template.version_numeric"] >= 3125: systemd_target_filename = os.path.join( rpm_build_dir, "usr/lib/systemd/system/", "%s.service" % client_name) utils.EnsureDirExists(os.path.dirname(systemd_target_filename)) self.GenerateFile( os.path.join(tmp_dir, "dist/rpmbuild/grr-client.service.in"), systemd_target_filename) # Generate prelinking blacklist file prelink_target_filename = os.path.join(rpm_build_dir, "etc/prelink.conf.d", "%s.conf" % client_name) utils.EnsureDirExists(os.path.dirname(prelink_target_filename)) self.GenerateFile( os.path.join(tmp_dir, "dist/rpmbuild/prelink_blacklist.conf.in"), prelink_target_filename) # Create a client config. client_context = ["Client Context"] + self.context client_config_content = self.GetClientConfig(client_context) with open( os.path.join( target_binary_dir, config.CONFIG.Get("ClientBuilder.config_filename", context=self.context)), "wb") as fd: fd.write(client_config_content) # Set the daemon to executable. os.chmod(os.path.join(target_binary_dir, client_binary_name), 0755) client_arch = config.CONFIG.Get("Template.arch", context=self.context) if client_arch == "amd64": client_arch = "x86_64" command = [ rpmbuild_binary, "--define", "_topdir " + rpm_root_dir, "--target", client_arch, "--buildroot", rpm_buildroot_dir, "-bb", spec_filename ] try: subprocess.check_output(command, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: logging.error("Error calling %s.", command) logging.error(e.output) raise client_version = config.CONFIG.Get("Template.version_string", context=self.context) rpm_filename = os.path.join( rpm_rpms_dir, client_arch, "%s-%s-1.%s.rpm" % (client_name, client_version, client_arch)) utils.EnsureDirExists(os.path.dirname(output_path)) shutil.move(rpm_filename, output_path) logging.info("Created package %s", output_path) self.Sign(output_path) return output_path
def MakeDeployableBinary(self, template_path, output_path): """This will add the config to the client template and create a .deb.""" buildpackage_binary = "/usr/bin/dpkg-buildpackage" if not os.path.exists(buildpackage_binary): logging.error( "dpkg-buildpackage not found, unable to repack client.") return with utils.TempDirectory() as tmp_dir: template_dir = os.path.join(tmp_dir, "dist") utils.EnsureDirExists(template_dir) zf = zipfile.ZipFile(template_path) for name in zf.namelist(): dirname = os.path.dirname(name) utils.EnsureDirExists(os.path.join(template_dir, dirname)) with open(os.path.join(template_dir, name), "wb") as fd: fd.write(zf.read(name)) # Generate the dpkg files. self.GenerateDPKGFiles(tmp_dir) # Create a client config. client_context = ["Client Context"] + self.context client_config_content = self.GetClientConfig(client_context) # We need to strip leading /'s or .join will ignore everything that comes # before it. target_dir = config.CONFIG.Get("ClientBuilder.target_dir", context=self.context).lstrip("/") agent_dir = os.path.join( template_dir, "debian", config.CONFIG.Get("ClientBuilder.package_name", context=self.context), target_dir) with open( os.path.join( agent_dir, config.CONFIG.Get("ClientBuilder.config_filename", context=self.context)), "wb") as fd: fd.write(client_config_content) # Set the daemon to executable. os.chmod( os.path.join( agent_dir, config.CONFIG.Get("Client.binary_name", context=self.context)), 0755) arch = config.CONFIG.Get("Template.arch", context=self.context) try: old_working_dir = os.getcwd() except OSError: old_working_dir = os.environ.get("HOME", "/tmp") try: os.chdir(template_dir) command = [ buildpackage_binary, "-uc", "-d", "-b", "-a%s" % arch ] try: subprocess.check_output(command, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: if "Failed to sign" not in e.output: logging.error("Error calling %s.", command) logging.error(e.output) raise filename_base = config.CONFIG.Get( "ClientBuilder.debian_package_base", context=self.context) output_base = config.CONFIG.Get( "ClientRepacker.output_basename", context=self.context) finally: try: os.chdir(old_working_dir) except OSError: pass utils.EnsureDirExists(os.path.dirname(output_path)) for extension in [ ".changes", config.CONFIG.Get("ClientBuilder.output_extension", context=self.context) ]: input_name = "%s%s" % (filename_base, extension) output_name = "%s%s" % (output_base, extension) shutil.move( os.path.join(tmp_dir, input_name), os.path.join(os.path.dirname(output_path), output_name)) logging.info("Created package %s", output_path) return output_path
def GenerateDPKGFiles(self, template_path): """Generates the files needed by dpkg-buildpackage.""" # Rename the generated binaries to the correct name. template_binary_dir = os.path.join(template_path, "dist/debian/grr-client") package_name = config.CONFIG.Get("ClientBuilder.package_name", context=self.context) target_binary_dir = os.path.join( template_path, "dist/debian/%s%s" % (package_name, config.CONFIG.Get("ClientBuilder.target_dir", context=self.context))) if package_name == "grr-client": # Need to rename the template path or the move will fail. shutil.move(template_binary_dir, "%s-template" % template_binary_dir) template_binary_dir = "%s-template" % template_binary_dir utils.EnsureDirExists(os.path.dirname(target_binary_dir)) shutil.move(template_binary_dir, target_binary_dir) shutil.move( os.path.join(target_binary_dir, "grr-client"), os.path.join( target_binary_dir, config.CONFIG.Get("Client.binary_name", context=self.context))) deb_in_dir = os.path.join(template_path, "dist/debian/debian.in/") self.GenerateDirectory(deb_in_dir, os.path.join(template_path, "dist/debian"), [("grr-client", package_name)]) # Generate directories for the /usr/sbin link. utils.EnsureDirExists( os.path.join(template_path, "dist/debian/%s/usr/sbin" % package_name)) # Generate the nanny template. This only exists from client version 3.1.2.5 # onwards. if config.CONFIG["Template.version_numeric"] >= 3125: self.GenerateFile(os.path.join(target_binary_dir, "nanny.sh.in"), os.path.join(target_binary_dir, "nanny.sh")) # Generate the upstart template. self.GenerateFile( os.path.join(template_path, "dist/debian/upstart.in/grr-client.conf"), os.path.join(template_path, "dist/debian/%s.upstart" % package_name)) # Generate the initd template. The init will not run if it detects upstart # is present. self.GenerateFile( os.path.join(template_path, "dist/debian/initd.in/grr-client"), os.path.join(template_path, "dist/debian/%s.init" % package_name)) # Generate the systemd unit file. self.GenerateFile( os.path.join(template_path, "dist/debian/systemd.in/grr-client.service"), os.path.join(template_path, "dist/debian/%s.service" % package_name)) # Clean up the template dirs. shutil.rmtree(deb_in_dir) shutil.rmtree(os.path.join(template_path, "dist/debian/upstart.in")) shutil.rmtree(os.path.join(template_path, "dist/debian/initd.in")) shutil.rmtree(os.path.join(template_path, "dist/debian/systemd.in"))
def MakeSelfExtractingZip(self, payload_data, output_path): """Repack the installer into the payload. Args: payload_data: data payload for zip file output_path: filename for the zip output Raises: RuntimeError: if the ClientBuilder.unzipsfx_stub doesn't require admin. Returns: output_path: filename string of zip output file """ context = self.context + ["Client Context"] src_zip = zipfile.ZipFile(cStringIO.StringIO(payload_data), mode="r") zip_data = cStringIO.StringIO() output_zip = zipfile.ZipFile(zip_data, mode="w", compression=zipfile.ZIP_DEFLATED) config_file_name = config.CONFIG.Get("ClientBuilder.config_filename", context=context) # Copy the rest of the files from the package to the new zip. for template_file in src_zip.namelist(): if template_file != config_file_name: # Avoid writing the config file twice if we're repacking a binary that # has already been run through deployment. We write it in the next step, # so no need to copy over from the original here. CopyFileInZip(src_zip, template_file, output_zip) client_config_content = self.GetClientConfig(context) output_zip.writestr(config_file_name, client_config_content, compress_type=zipfile.ZIP_STORED) # The zip file comment is used by the self extractor to run # the installation script output_zip.comment = "$AUTORUN$>%s" % config.CONFIG.Get( "ClientBuilder.autorun_command_line", context=context) output_zip.close() utils.EnsureDirExists(os.path.dirname(output_path)) with open(output_path, "wb") as fd: # First write the installer stub stub_data = cStringIO.StringIO() unzipsfx_stub = config.CONFIG.Get("ClientBuilder.unzipsfx_stub", context=context) stub_raw = open(unzipsfx_stub, "rb").read() # Check stub has been compiled with the requireAdministrator manifest. if "level=\"requireAdministrator" not in stub_raw: raise RuntimeError( "Bad unzip binary in use. Not compiled with the" "requireAdministrator manifest option.") stub_data.write(stub_raw) # If in verbose mode, modify the unzip bins PE header to run in console # mode for easier debugging. SetPeSubsystem(stub_data, console=config.CONFIG.Get("ClientBuilder.console", context=context)) # Now patch up the .rsrc section to contain the payload. end_of_file = zip_data.tell() + stub_data.tell() # This is the IMAGE_SECTION_HEADER.Name which is also the start of # IMAGE_SECTION_HEADER. offset_to_rsrc = stub_data.getvalue().find(".rsrc") # IMAGE_SECTION_HEADER.PointerToRawData is a 32 bit int. stub_data.seek(offset_to_rsrc + 20) start_of_rsrc_section = struct.unpack("<I", stub_data.read(4))[0] # Adjust IMAGE_SECTION_HEADER.SizeOfRawData to span from the old start to # the end of file. stub_data.seek(offset_to_rsrc + 16) stub_data.write( struct.pack("<I", end_of_file - start_of_rsrc_section)) # Concatenate stub and zip file. out_data = cStringIO.StringIO() out_data.write(stub_data.getvalue()) out_data.write(zip_data.getvalue()) # Then write the actual output file. fd.write(out_data.getvalue()) if self.signer: self.signer.SignFile(output_path) logging.info("Deployable binary generated at %s", output_path) return output_path