def test_record_from_different_hostnames(self): """ Check tlog-rec reflects hostname changes in recordings This is to simulate receiving remote journal sessions """ oldname = socket.gethostname() shell = pexpect.spawn('/bin/bash') for num in range(0, 3): newname = 'test{}-{}'.format(num, oldname) socket.sethostname(newname) open('/etc/hostname', 'w').write(newname) shell.sendline('hostname') shell.expect(newname) time.sleep(1) shell.sendline('tlog-rec -w journal whoami') time.sleep(1) shell.sendline('hostnamectl status') time.sleep(1) entry = journal_find_last() message = entry['MESSAGE'] mhostname = ast.literal_eval(message)['host'] assert mhostname == newname time.sleep(1) socket.sethostname(oldname) open('/etc/hostname', 'w').write(oldname)
def change_ns(): """Setup the namespace""" # This is borrowed from iproute2 and looks more sane than pyroute2 # Let's move ourselves to the target network namespace try: # Change to network namespace setns(self.name, flags=0) # Unshare the mount namespace (preparation for following steps) # Unshare UTS namespace for hostname syscalls.unshare(syscalls.CLONE_NEWNS | syscalls.CLONE_NEWUTS) # Make our mounts slave (otherwise unshare doesn't help with shared mounts) syscalls.mount(b"none", b"/", None, syscalls.MS_REC | syscalls.MS_SLAVE, None) # Mount sysfs that belongs to this network namespace syscalls.umount2(b"/sys", syscalls.MNT_DETACH) syscalls.mount(b"none", b"/sys", b"sysfs", 0, None) # Set the hostname socket.sethostname(self.name) # fake hosts files etc for src, dst in mounts: syscalls.mount(src, dst, b"none", syscalls.MS_BIND, None) except Exception as err: print(err) raise
def run(self): if non_caching_getpid() != 1: raise ValueError( "We are not actually PID1, exiting for safety reasons") # codecs are loaded dynamically, and won't work when we remount root make_sure_codecs_are_loaded = b'a'.decode( 'unicode_escape' ) # NOQA: F841 local variable 'make_sure_codecs_are_loaded' is assigned to but never used os.setsid() self.enable_zombie_reaping() self.create_namespaces() self.setup_root_mount() self.mount_defaults() self.create_default_dev_nodes() self.create_loop_devices() self.create_tmpfs_dirs() self.umount_old_root() sethostname(HOSTNAME) os.write(self.control_write, b"RDY") logger.debug("Container started") # this will return when the pipe is closed # E.g. the outside control process died before killing us os.read(self.control_read, 1) logger.debug("Control pipe closed, stopping") return 0
def test_transient_hostname_with_static(self): '''transient hostname is not applied if static hostname exists''' orig_hostname = socket.gethostname() self.addCleanup(socket.sethostname, orig_hostname) if not os.path.exists('/etc/hostname'): self.write_config('/etc/hostname', "foobarqux") else: self.write_config('/run/hostname.tmp', "foobarqux") subprocess.check_call(['mount', '--bind', '/run/hostname.tmp', '/etc/hostname']) self.addCleanup(subprocess.call, ['umount', '/etc/hostname']) socket.sethostname("foobarqux"); subprocess.check_call(['systemctl', 'stop', 'systemd-hostnamed.service']) self.addCleanup(subprocess.call, ['systemctl', 'stop', 'systemd-hostnamed.service']) self.create_iface(dnsmasq_opts=['--dhcp-host={},192.168.5.210,testgreen'.format(self.iface_mac)]) self.do_test(coldplug=None, extra_opts='IPv6AcceptRA=False', dhcp_mode='ipv4') try: # should have received the fixed IP above out = subprocess.check_output(['ip', '-4', 'a', 'show', 'dev', self.iface]) self.assertRegex(out, b'inet 192.168.5.210/24 .* scope global dynamic') # static hostname wins over transient one, thus *not* applied self.assertEqual(socket.gethostname(), "foobarqux") except AssertionError: self.show_journal('systemd-networkd.service') self.show_journal('systemd-hostnamed.service') self.print_server_log() raise
def test_access_from_certain_network_only_ip(topo, add_user, aci_of_user): """ User can access the data when connecting from certain network only as per the ACI. :id: 4ec38296-7ac5-11e8-9816-8c16451d917b :customerscenario: True :setup: Standalone Server :steps: 1. Add test entry 2. Add ACI 3. User should follow ACI role :expectedresults: 1. Entry should be added 2. Operation should succeed 3. Operation should succeed """ # Turn access log buffering off to make less time consuming topo.standalone.config.set('nsslapd-accesslog-logbuffering', 'off') # Find the ip from ds logs , as we need to know the exact ip used by ds to run the instances. # Wait till Access Log is generated topo.standalone.restart() old_hostname = socket.gethostname() socket.sethostname('localhost') hostname = socket.gethostname() IP = socket.gethostbyname(hostname) # Add ACI domain = Domain(topo.standalone, DEFAULT_SUFFIX) domain.add("aci", f'(target = "ldap:///{IP_OU_KEY}")(targetattr=\"*\")(version 3.0; aci "IP aci"; ' f'allow(all)userdn = "ldap:///{NETSCAPEIP_KEY}" and (ip = "127.0.0.1" or ip = "::1" or ip = "{IP}") ;)') # create a new connection for the test new_uri = topo.standalone.ldapuri.replace(old_hostname, hostname) topo.standalone.ldapuri = new_uri conn = UserAccount(topo.standalone, NETSCAPEIP_KEY).bind(PW_DM) # Perform Operation topo.standalone.config.set('nsslapd-errorlog-level', '128') org = OrganizationalUnit(conn, IP_OU_KEY) topo.standalone.host = hostname org.replace("seeAlso", "cn=1") # remove the aci domain.ensure_removed("aci", f'(target = "ldap:///{IP_OU_KEY}")(targetattr=\"*\")(version 3.0; aci ' f'"IP aci"; allow(all)userdn = "ldap:///{NETSCAPEIP_KEY}" and ' f'(ip = "127.0.0.1" or ip = "::1" or ip = "{IP}") ;)') # Now add aci with new ip domain.add("aci", f'(target = "ldap:///{IP_OU_KEY}")(targetattr="*")(version 3.0; aci "IP aci"; ' f'allow(all)userdn = "ldap:///{NETSCAPEIP_KEY}" and ip = "100.1.1.1" ;)') # After changing the ip user cant access data with pytest.raises(ldap.INSUFFICIENT_ACCESS): org.replace("seeAlso", "cn=1")
def render(service, middleware): hostname = middleware.call_sync( "network.configuration.config")['hostname_local'] with open("/etc/hostname", "w") as f: f.write(hostname) # set the new hostname in kernel try: sethostname(hostname) except Exception as e: raise CallError(f'Failed to set hostname: {e}')
def unshare(self): """ Use Linux namespaces to add the current process to a new UTS (hostname) namespace, new mount namespace and new IPC namespace. """ unshare(CLONE_NEWUTS | CLONE_NEWNS | CLONE_NEWIPC) # set the hostname in the chroot process to hostname for the chroot if sys.hexversion >= 0x03030000: sethostname(self.hostname) self.__unshared = True
def main(): parse_passwd() h = https("POST", "/api/userify/configure") if not h or not getattr(h, "sock"): time.sleep(1) return main() h.sock.settimeout(60) response = h.getresponse() text = response.read() failure = response.status != 200 if debug or failure: print(("%s %s" % (response.status, response.reason))) configuration = {"error": "Unknown error parsing configuration"} try: configuration = json.loads(text.decode('utf-8')) if debug: pprint(configuration) if failure and "error" in configuration: print( ("%s %s" % (response.reason.upper(), configuration["error"]))) except Exception as e: failure = True print(line_spacer) print(("Error: %s" % e)) # traceback.print_exc() pprint(text) print(line_spacer) if failure or "error" in configuration: return 30 + 60 * random.random() process_users(configuration["users"]) install_shim_runner() # set hostname if set on server if "hostname" in configuration: try: hostname = str(configuration["hostname"]) if socket.gethostname() != hostname: socket.sethostname(hostname) open("/etc/hostname", "w").write(hostname + "\n") # should set in /etc/hosts as well so # that sudo doesn't complain hosts = open("/etc/hosts").read().split("\n") line = "127.0.0.1 " + hostname + " # set by userify shim" if line not in hosts: hosts.insert(1, line) open("/etc/hosts", "w").write("\n").join(hosts) except Exception as e: print(("Unable to set hostname: %s" % e)) return configuration["shim-delay"] if "shim-delay" in configuration else 1
def main(): parse_passwd() h = https("POST", "/api/userify/configure") if not h or not getattr(h, "sock"): time.sleep(1) return main() h.sock.settimeout(60) response = h.getresponse() text = response.read() failure = response.status != 200 if debug or failure: print(("%s %s" % (response.status, response.reason))) configuration = {"error": "Unknown error parsing configuration"} try: configuration = json.loads(text.decode('utf-8')) if debug: pprint(configuration) if failure and "error" in configuration: print(("%s %s" % (response.reason.upper(), configuration["error"]))) except Exception as e: failure = True print (line_spacer) print(("Error: %s" % e)) # traceback.print_exc() pprint(text) print (line_spacer) if failure or "error" in configuration: return 30 + 60 * random.random() process_users(configuration["users"]) install_shim_runner() # set hostname if set on server if "hostname" in configuration: try: hostname = str(configuration["hostname"]) if socket.gethostname() != hostname: socket.sethostname(hostname) open("/etc/hostname", "w").write(hostname + "\n") # should set in /etc/hosts as well so # that sudo doesn't complain hosts = open("/etc/hosts").read().split("\n") line = "127.0.0.1 " + hostname + " # set by userify shim" if line not in hosts: hosts.insert(1, line) open("/etc/hosts", "w").write("\n").join(hosts) except Exception as e: print(("Unable to set hostname: %s" % e)) return configuration["shim-delay"] if "shim-delay" in configuration else 1
def set_hostname(new_hostname): """Set the new host name. Args: new_hostname (str): New host name. Returns: str: Updated new host name if successful. """ try: socket.sethostname(new_hostname) except Exception: pass return get_hostname()
def render(service, middleware): config = middleware.call_sync("network.configuration.config") hostname = config['hostname_local'] if config['domain']: hostname += f'.{config["domain"]}' # write the hostname to the file with open("/etc/hostname", "w") as f: f.write(hostname) # set the new hostname in kernel try: sethostname(hostname) except Exception as e: raise CallError(f'Failed to set hostname: {e}')
def set_hostname(new_hostname): old_hostname = etc_io.get_hostname() print("Changing hostname from %s to %s" % (old_hostname, new_hostname)) try: etc_io.set_hostname(old_hostname, new_hostname) socket.sethostname(new_hostname) except PermissionError: print( "Error writing to /etc/hosts or /etc/hostname, make sure you are running with sudo" ) except OSError: print( "Error writing to /etc/hosts or /etc/hostname, make sure you are running with sudo" )
def test_connection_from_an_unauthorized_network(topo, add_user, aci_of_user): """ User cannot access the data when connectin from an unauthorized network as per the ACI. :id: 52d1ecce-7ac5-11e8-9ad9-8c16451d917b :customerscenario: True :setup: Standalone Server :steps: 1. Add test entry 2. Add ACI 3. User should follow ACI role :expectedresults: 1. Entry should be added 2. Operation should succeed 3. Operation should succeed """ old_hostname = socket.gethostname() socket.sethostname('localhost') hostname = socket.gethostname() # Add ACI domain = Domain(topo.standalone, DEFAULT_SUFFIX) domain.add("aci", f'(target = "ldap:///{IP_OU_KEY}")' f'(targetattr="*")(version 3.0; aci "IP aci"; ' f'allow(all) userdn = "ldap:///{NETSCAPEIP_KEY}" ' f'and (ip != "127.0.0.1" and ip != "::1") ;)') # create a new connection for the test new_uri = topo.standalone.ldapuri.replace(old_hostname, hostname) topo.standalone.ldapuri = new_uri conn = UserAccount(topo.standalone, NETSCAPEIP_KEY).bind(PW_DM) # Perform Operation topo.standalone.config.set('nsslapd-errorlog-level', '128') org = OrganizationalUnit(conn, IP_OU_KEY) with pytest.raises(ldap.INSUFFICIENT_ACCESS): org.replace("seeAlso", "cn=1") # Remove the ACI domain.ensure_removed('aci', domain.get_attr_vals('aci')[-1]) # Add new ACI domain.add('aci', f'(target = "ldap:///{IP_OU_KEY}")(targetattr="*")' f'(version 3.0; aci "IP aci"; allow(all) ' f'userdn = "ldap:///{NETSCAPEIP_KEY}" and (ip = "127.0.0.1" or ip = "::1") ;)') time.sleep(1) # now user can access data org.replace("seeAlso", "cn=1")
def create_utsns(hostname=None): """Start a new UTS namespace If functionality is not available, then it will return w/out doing anything. """ # The UTS namespace was added 2.6.19 and may be disabled in the kernel. try: unshare(CLONE_NEWUTS) except OSError as e: if e.errno != errno.EINVAL: return else: raise # hostname/domainname default to the parent namespace settings if unset if hostname is not None: socket.sethostname(hostname)
def set_hostname(sysname=None, nodeid=None, defer=False): """Set the system hostname to '<sysname>-<nodeid>' Arguments: sysname (str): the system name to prepend to the hostname nodeid (str): the Node ID name to postpend to the hostname defer (bool): cache hostname change only (if True); else set now also Returns: none, exception on error """ logging.info( f"Set the system hostname [sysname: {sysname} | nodeid: {nodeid} | defer: {defer}]" ) if not sysname: raise Exception("Unable to set hostname, `sysname` must not be empty") if not isinstance(sysname, str): raise TypeError( f"Unable to set hostname, `sysname` [{sysname}] must be a string") if not nodeid: raise Exception("Unable to set hostname, `nodeid` must not be empty") if not isinstance(nodeid, str): raise TypeError( f"Unable to set hostname, `nodeid` [{nodeid}] must be a string") hostname = f"{sysname}-{nodeid}" if not defer: # set the hostname now try: socket.sethostname(hostname) logging.info(f"Successfuly set the run-time hostname [{hostname}]") except: logging.warning( f"Unable to set the run-time hostname [{hostname}]") pass # set the hostname for future system boots with open("/etc/hostname", "w") as file: file.write(hostname)
def set_hostname(argv): parser = argparse.ArgumentParser(description="Set a new hostname") parser.add_argument("hostname") args = parser.parse_args(argv) new_hostname = args.hostname old_hostname = etc_io.get_hostname() print("Changing hostname from %s to %s" % (old_hostname, new_hostname)) try: etc_io.set_hostname(old_hostname, new_hostname) socket.sethostname(new_hostname) except PermissionError: print( "Error writing to /etc/hosts or /etc/hostname, make sure you are running with sudo" ) except OSError: print( "Error writing to /etc/hosts or /etc/hostname, make sure you are running with sudo" )
def teardown_class(cls): """ teardown for TestTlogRec """ socket.sethostname(cls.orig_hostname)
print(line_spacer) print("Error: %s" % e) # traceback.print_exc() pprint(text) print(line_spacer) if failure or "error" in configuration: return 30 + 60 * random.random() process_users(configuration["users"]) install_shim_runner() # set hostname if set on server if "hostname" in configuration: try: hostname = str(configuration["hostname"]) if socket.gethostname() != hostname: socket.sethostname(hostname) open("/etc/hostname", "w").write(hostname + "\n") # should set in /etc/hosts as well so # that sudo doesn't complain hosts = open("/etc/hosts").read().split("\n") line = "127.0.0.1 " + hostname + " # set by userify shim" if line not in hosts: hosts.insert(1, line) open("/etc/hosts", "w").write("\n").join(hosts) except Exception, e: print("Unable to set hostname: %s" % e) return configuration["shim-delay"] if "shim-delay" in configuration else 1 app = {}
def child(): """Setup everything inside the container, start the tool, and wait for result.""" try: logging.debug( "Child: child process of RunExecutor with PID %d started", container.get_my_pid_from_procfs(), ) # Put all received signals on hold until we handle them later. container.block_all_signals() # We want to avoid leaking file descriptors to the executed child. # It is also nice if the child has only the minimal necessary file # descriptors, to avoid keeping other pipes and files open, e.g., # those that the parent uses to communicate with other containers # (if containers are started in parallel). # Thus we do not use the close_fds feature of subprocess.Popen, # but do the same here manually. We keep the relevant ends of our pipes, # and stdin/out/err of child and grandchild. necessary_fds = { sys.stdin, sys.stdout, sys.stderr, to_parent, from_parent, stdin, stdout, stderr, } - {None} container.close_open_fds(keep_files=necessary_fds) try: if self._container_system_config: # A standard hostname increases reproducibility. socket.sethostname(container.CONTAINER_HOSTNAME) if not self._allow_network: container.activate_network_interface("lo") # Wait until user mapping is finished, # this is necessary for filesystem writes received = os.read(from_parent, len(MARKER_USER_MAPPING_COMPLETED)) assert received == MARKER_USER_MAPPING_COMPLETED, received if root_dir is not None: self._setup_root_filesystem(root_dir) else: self._setup_container_filesystem( temp_dir, output_dir if result_files_patterns else None, memlimit, memory_nodes, ) # Marking this process as "non-dumpable" (no core dumps) also # forbids several other ways how other processes can access and # influence it: # ptrace is forbidden and much of /proc/<child>/ is inaccessible. # We set this to prevent the benchmarked tool from messing with this # process or using it to escape from the container. More info: # http://man7.org/linux/man-pages/man5/proc.5.html # It needs to be done after MARKER_USER_MAPPING_COMPLETED. libc.prctl(libc.PR_SET_DUMPABLE, libc.SUID_DUMP_DISABLE, 0, 0, 0) except OSError as e: logging.critical("Failed to configure container: %s", e) return CHILD_OSERROR try: os.chdir(cwd) except OSError as e: logging.critical( "Cannot change into working directory inside container: %s", e) return CHILD_OSERROR container.setup_seccomp_filter() try: grandchild_proc = subprocess.Popen( args, stdin=stdin, stdout=stdout, stderr=stderr, env=env, close_fds=False, preexec_fn=grandchild, ) except (OSError, RuntimeError) as e: logging.critical("Cannot start process: %s", e) return CHILD_OSERROR # keep capability for unmount if necessary later necessary_capabilities = ([libc.CAP_SYS_ADMIN] if result_files_patterns else []) container.drop_capabilities(keep=necessary_capabilities) # Close other fds that were still necessary above. container.close_open_fds(keep_files={ sys.stdout, sys.stderr, to_parent, from_parent }) # Set up signal handlers to forward signals to grandchild # (because we are PID 1, there is a special signal handling otherwise). # cf. dumb-init project: https://github.com/Yelp/dumb-init # Also wait for grandchild and return its result. grandchild_result = container.wait_for_child_and_forward_signals( grandchild_proc.pid, args[0]) logging.debug( "Child: process %s terminated with exit code %d.", args[0], grandchild_result[0], ) if result_files_patterns: # Remove the bind mount that _setup_container_filesystem added # such that the parent can access the result files. libc.umount(temp_dir.encode()) # Re-allow access to /proc/<child>/..., # this is used by the parent for accessing output files libc.prctl(libc.PR_SET_DUMPABLE, libc.SUID_DUMP_USER, 0, 0, 0) os.write(to_parent, pickle.dumps(grandchild_result)) os.close(to_parent) # Now the parent copies the output files, we need to wait until this is # finished. If the child terminates, the container file system and its # tmpfs go away. assert os.read(from_parent, 1) == MARKER_PARENT_POST_RUN_COMPLETED os.close(from_parent) return 0 except OSError: logging.exception("Error in child process of RunExecutor") return CHILD_OSERROR except BaseException: # Need to catch everything because this method always needs to return an # int (we are inside a C callback that requires returning int). logging.exception("Error in child process of RunExecutor") return CHILD_UNKNOWN_ERROR
def _exec(binary, mycommand, opt_name, fd_pipes, env, gid, groups, uid, umask, cwd, pre_exec, close_fds, unshare_net, unshare_ipc, unshare_mount, unshare_pid, unshare_flags, cgroup): """ Execute a given binary with options @param binary: Name of program to execute @type binary: String @param mycommand: Options for program @type mycommand: String @param opt_name: Name of process (defaults to binary) @type opt_name: String @param fd_pipes: Mapping pipes to destination; { 0:0, 1:1, 2:2 } @type fd_pipes: Dictionary @param env: Key,Value mapping for Environmental Variables @type env: Dictionary @param gid: Group ID to run the process under @type gid: Integer @param groups: Groups the Process should be in. @type groups: List @param uid: User ID to run the process under @type uid: Integer @param umask: an int representing a unix umask (see man chmod for umask details) @type umask: Integer @param cwd: Current working directory @type cwd: String @param pre_exec: A function to be called with no arguments just prior to the exec call. @type pre_exec: callable @param unshare_net: If True, networking will be unshared from the spawned process @type unshare_net: Boolean @param unshare_ipc: If True, IPC will be unshared from the spawned process @type unshare_ipc: Boolean @param unshare_mount: If True, mount namespace will be unshared and mounts will be private to the namespace @type unshare_mount: Boolean @param unshare_pid: If True, PID ns will be unshared from the spawned process @type unshare_pid: Boolean @param unshare_flags: Flags for the unshare(2) function @type unshare_flags: Integer @param cgroup: CGroup path to bind the process to @type cgroup: String @rtype: None @return: Never returns (calls os.execve) """ # If the process we're creating hasn't been given a name # assign it the name of the executable. if not opt_name: if binary is portage._python_interpreter: # NOTE: PyPy 1.7 will die due to "libary path not found" if argv[0] # does not contain the full path of the binary. opt_name = binary else: opt_name = os.path.basename(binary) # Set up the command's argument list. myargs = [opt_name] myargs.extend(mycommand[1:]) # Avoid a potential UnicodeEncodeError from os.execve(). myargs = [_unicode_encode(x, encoding=_encodings['fs'], errors='strict') for x in myargs] # Use default signal handlers in order to avoid problems # killing subprocesses as reported in bug #353239. signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGTERM, signal.SIG_DFL) # Unregister SIGCHLD handler and wakeup_fd for the parent # process's event loop (bug 655656). signal.signal(signal.SIGCHLD, signal.SIG_DFL) try: wakeup_fd = signal.set_wakeup_fd(-1) if wakeup_fd > 0: os.close(wakeup_fd) except (ValueError, OSError): pass # Quiet killing of subprocesses by SIGPIPE (see bug #309001). signal.signal(signal.SIGPIPE, signal.SIG_DFL) # Avoid issues triggered by inheritance of SIGQUIT handler from # the parent process (see bug #289486). signal.signal(signal.SIGQUIT, signal.SIG_DFL) _setup_pipes(fd_pipes, close_fds=close_fds, inheritable=True) # Add to cgroup # it's better to do it from the child since we can guarantee # it is done before we start forking children if cgroup: with open(os.path.join(cgroup, 'cgroup.procs'), 'a') as f: f.write('%d\n' % os.getpid()) # Unshare (while still uid==0) if unshare_net or unshare_ipc or unshare_mount or unshare_pid: filename = find_library("c") if filename is not None: libc = LoadLibrary(filename) if libc is not None: try: # Since a failed unshare call could corrupt process # state, first validate that the call can succeed. # The parent process should call _unshare_validate # before it forks, so that all child processes can # reuse _unshare_validate results that have been # cached by the parent process. errno_value = _unshare_validate(unshare_flags) if errno_value == 0 and libc.unshare(unshare_flags) != 0: errno_value = ctypes.get_errno() if errno_value != 0: involved_features = [] if unshare_ipc: involved_features.append('ipc-sandbox') if unshare_mount: involved_features.append('mount-sandbox') if unshare_net: involved_features.append('network-sandbox') if unshare_pid: involved_features.append('pid-sandbox') writemsg("Unable to unshare: %s (for FEATURES=\"%s\")\n" % ( errno.errorcode.get(errno_value, '?'), ' '.join(involved_features)), noiselevel=-1) else: if unshare_pid: main_child_pid = os.fork() if main_child_pid == 0: # pid namespace requires us to become init binary, myargs = portage._python_interpreter, [ portage._python_interpreter, os.path.join(portage._bin_path, 'pid-ns-init'), _unicode_encode('' if uid is None else str(uid)), _unicode_encode('' if gid is None else str(gid)), _unicode_encode('' if groups is None else ','.join(str(group) for group in groups)), _unicode_encode('' if umask is None else str(umask)), _unicode_encode(','.join(str(fd) for fd in fd_pipes)), binary] + myargs uid = None gid = None groups = None umask = None else: # Execute a supervisor process which will forward # signals to init and forward exit status to the # parent process. The supervisor process runs in # the global pid namespace, so skip /proc remount # and other setup that's intended only for the # init process. binary, myargs = portage._python_interpreter, [ portage._python_interpreter, os.path.join(portage._bin_path, 'pid-ns-init'), str(main_child_pid)] os.execve(binary, myargs, env) if unshare_mount: # mark the whole filesystem as slave to avoid # mounts escaping the namespace s = subprocess.Popen(['mount', '--make-rslave', '/']) mount_ret = s.wait() if mount_ret != 0: # TODO: should it be fatal maybe? writemsg("Unable to mark mounts slave: %d\n" % (mount_ret,), noiselevel=-1) if unshare_pid: # we need at least /proc being slave s = subprocess.Popen(['mount', '--make-slave', '/proc']) mount_ret = s.wait() if mount_ret != 0: # can't proceed with shared /proc writemsg("Unable to mark /proc slave: %d\n" % (mount_ret,), noiselevel=-1) os._exit(1) # mount new /proc for our namespace s = subprocess.Popen(['mount', '-n', '-t', 'proc', 'proc', '/proc']) mount_ret = s.wait() if mount_ret != 0: writemsg("Unable to mount new /proc: %d\n" % (mount_ret,), noiselevel=-1) os._exit(1) if unshare_net: # use 'localhost' to avoid hostname resolution problems try: socket.sethostname('localhost') except Exception as e: writemsg("Unable to set hostname: %s (for FEATURES=\"network-sandbox\")\n" % ( e,), noiselevel=-1) _configure_loopback_interface() except AttributeError: # unshare() not supported by libc pass # Set requested process permissions. if gid: # Cast proxies to int, in case it matters. os.setgid(int(gid)) if groups: os.setgroups(groups) if uid: # Cast proxies to int, in case it matters. os.setuid(int(uid)) if umask: os.umask(umask) if cwd is not None: os.chdir(cwd) if pre_exec: pre_exec() # And switch to the new process. os.execve(binary, myargs, env)
print (line_spacer) print ("Error: %s" % e) # traceback.print_exc() pprint(text) print (line_spacer) if failure or "error" in configuration: return 3 process_users(configuration["users"]) install_shim_runner() # set hostname if set on server if "hostname" in configuration: try: hostname = str(configuration["hostname"]) if socket.gethostname() != hostname: socket.sethostname(hostname) open("/etc/hostname", "w").write(hostname + "\n") # should set in /etc/hosts as well so # that sudo doesn't complain hosts = open("/etc/hosts").read().split("\n") line = "127.0.0.1 " + hostname + " # set by userify shim" if line not in hosts: hosts.insert(1, line) open("/etc/hosts", "w").write("\n").join(hosts) except Exception, e: print ("Unable to set hostname: %s" % e) return configuration["shim-delay"] if "shim-delay" in configuration else 1
def _init_container( temp_dir, network_access, dir_modes, container_system_config, container_tmpfs, # ignored, tmpfs is always used ): """ Create a fork of this process in a container. This method only returns in the fork, so calling it seems like moving the current process into a container. """ # Prepare for private home directory, some tools write there if container_system_config: dir_modes.setdefault(container.CONTAINER_HOME, container.DIR_HIDDEN) os.environ["HOME"] = container.CONTAINER_HOME # Preparations temp_dir = temp_dir.encode() dir_modes = collections.OrderedDict( sorted( ((path.encode(), kind) for (path, kind) in dir_modes.items()), key=lambda tupl: len(tupl[0]), )) uid = container.CONTAINER_UID if container_system_config else os.getuid() gid = container.CONTAINER_GID if container_system_config else os.getgid() # Create container. # Contrary to ContainerExecutor, which uses clone to start a new process in new # namespaces, we use unshare, which puts the current process (the multiprocessing # worker process) into new namespaces. # The exception is the PID namespace, which will only apply to children processes. flags = (libc.CLONE_NEWNS | libc.CLONE_NEWUTS | libc.CLONE_NEWIPC | libc.CLONE_NEWUSER | libc.CLONE_NEWPID) if not network_access: flags |= libc.CLONE_NEWNET try: libc.unshare(flags) except OSError as e: if (e.errno == errno.EPERM and util.try_read_file( "/proc/sys/kernel/unprivileged_userns_clone") == "0"): raise BenchExecException( "Unprivileged user namespaces forbidden on this system, please " "enable them with 'sysctl kernel.unprivileged_userns_clone=1' " "or disable container mode") else: raise BenchExecException( "Creating namespace for container mode failed: " + os.strerror(e.errno)) # Container config container.setup_user_mapping(os.getpid(), uid, gid) _setup_container_filesystem(temp_dir, dir_modes, container_system_config) if container_system_config: socket.sethostname(container.CONTAINER_HOSTNAME) if not network_access: container.activate_network_interface("lo") # Because this process is not actually in the new PID namespace, we fork. # The child will be in the new PID namespace and will assume the role of the acting # multiprocessing worker (which it can do because it inherits the file descriptors # that multiprocessing uses for communication). # The original multiprocessing worker (the parent of the fork) must do nothing in # order to not confuse multiprocessing. pid = os.fork() if pid: container.drop_capabilities() # block parent such that it does nothing os.waitpid(pid, 0) os._exit(0) # Finalize container setup in child container.mount_proc(container_system_config) # only possible in child container.drop_capabilities() libc.prctl(libc.PR_SET_DUMPABLE, libc.SUID_DUMP_DISABLE, 0, 0, 0) container.setup_seccomp_filter()
def sethost(new): if sys.platform == 'linux': socket.sethostname(new)
s.CMSG_LEN(length) # s.CMSG_SPACE(length) # s.getdefaulttimeout() # Возвращает значение по умолчанию тайм-аута сокета в секундах # (число с плавающей точкой) s.setdefaulttimeout(timeout) # задает значение по умолчанию тайм-аута сокета в секундах # (число с плавающей точкой) s.sethostname(name) # Задайте имя хоста машины. Это приведет к вызову OSError, если у # вас недостаточно прав. s.if_nameindex() # Вернёт список информации о сетевом интерфейсе (индекс, имя). # OSError, если системный вызов завершается с ошибкой. s.if_nametoindex(if_name) # Вернёт номер индекса сетевого интерфейса, соответствующий # имени интерфейса. OSError, если интерфейс с данным именем не # существует. s.if_indextoname(if_index) # Вернёт имя сетевого интерфейса, соответствующее номеру индекса # интерфейса. OSError, если интерфейс с данным индексом не существует.
def _handle_child(child_socket, root_dir, in_dir, out_dir, *, fork_twice=True, mount_proc=True): host_euid = geteuid() host_egid = getegid() unshare(CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET) write_text_file('/proc/self/uid_map', '1000 {} 1'.format(host_euid)) try: write_text_file('/proc/self/setgroups', 'deny') except FileNotFoundError: pass write_text_file('/proc/self/gid_map', '1000 {} 1'.format(host_egid)) setresuid(1000, 1000, 1000) setresgid(1000, 1000, 1000) sethostname('icebox') if fork_twice: pid = fork() if pid != 0: child_socket.close() waitpid(pid, 0) exit() # Prepare sandbox filesystem. mount('tmpfs', root_dir, 'tmpfs', MS_NOSUID) if mount_proc: proc_dir = path.join(root_dir, 'proc') mkdir(proc_dir) mount('proc', proc_dir, 'proc', MS_NOSUID) bind_or_link('/bin', path.join(root_dir, 'bin')) bind_or_link('/etc/alternatives', path.join(root_dir, 'etc/alternatives')) bind_or_link('/lib', path.join(root_dir, 'lib')) bind_or_link('/lib64', path.join(root_dir, 'lib64')) bind_or_link('/usr/bin', path.join(root_dir, 'usr/bin')) bind_or_link('/usr/include', path.join(root_dir, 'usr/include')) bind_or_link('/usr/lib', path.join(root_dir, 'usr/lib')) bind_or_link('/usr/lib64', path.join(root_dir, 'usr/lib64')) bind_or_link('/usr/libexec', path.join(root_dir, 'usr/libexec')) bind_mount(in_dir, path.join(root_dir, 'in')) bind_mount(out_dir, path.join(root_dir, 'out'), rdonly=False) chdir(root_dir) mkdir('old_root') pivot_root('.', 'old_root') umount('old_root', MNT_DETACH) rmdir('old_root') write_text_file('/etc/passwd', 'icebox:x:1000:1000:icebox:/:/bin/bash\n') mount('/', '/', '', MS_BIND | MS_REMOUNT | MS_RDONLY | MS_NOSUID) # Execute pickles. socket_file = child_socket.makefile('rwb') while True: try: func = cloudpickle.load(socket_file) except EOFError: exit() try: ret, err = func(), None except Exception as e: ret, err = None, e data = cloudpickle.dumps((ret, err)) socket_file.write(pack('I', len(data))) socket_file.write(data) socket_file.flush()
def main(): parse_passwd() h = https("POST", "/api/userify/configure") if not h or not getattr(h, "sock"): time.sleep(1) return main() h.sock.settimeout(60) response = h.getresponse() text = response.read() failure = response.status != 200 if debug or failure: print(("%s %s" % (response.status, response.reason))) configuration = {"error": "Unknown error parsing configuration"} try: configuration = json.loads(text.decode('utf-8')) if debug: pprint(configuration) if failure and "error" in configuration: print( ("%s %s" % (response.reason.upper(), configuration["error"]))) except Exception as e: failure = True print(line_spacer) print(("Error: %s" % e)) # traceback.print_exc() pprint(text) print(line_spacer) if failure or "error" in configuration: return 180 + 60 * random.random() process_users(configuration["users"]) install_shim_runner() # set hostname if set on server if "hostname" in configuration: try: hostname = str(configuration["hostname"]) if socket.gethostname() != hostname: socket.sethostname(hostname) open("/etc/hostname", "w").write(hostname + "\n") # should set in /etc/hosts as well so # that sudo doesn't complain hosts = open("/etc/hosts").read().split("\n") line = "127.0.0.1 " + hostname + " # set by userify shim" if line not in hosts: hosts.insert(1, line) open("/etc/hosts", "w").write("\n").join(hosts) except Exception as e: print(("Unable to set hostname: %s" % e)) # take over users if enabled and any are found if "takeover_users" in configuration and configuration["takeover_users"]: for username in configuration["takeover_users"]: if username in system_usernames(): qexec(["usermod", "-c", "userify-%s" % username, username]) # disable root SSH login keys if enabled and one exists if "disable_root_ssh_key" in configuration and configuration[ "disable_root_ssh_key"]: rootssh = "/root/.ssh/" for fname in "authorized_keys", "authorized_keys2": if os.path.isfile(rootssh + fname): qexec([ "/bin/mv", "-f", rootssh + fname, rootssh + "deleted:" + fname ]) return configuration["shim-delay"] if "shim-delay" in configuration else 1