From faac0a66569df17dc76a6e92e58d40ebfc026b63 Mon Sep 17 00:00:00 2001 From: RoliSoft Date: Sun, 23 Oct 2016 01:55:10 +0300 Subject: [PATCH] User switching now happens directly, without involving WSL through lxrun. This way broken installations can be repaired without failing at the 'Probing the Linux subsystem' step. --- install.py | 79 +++++++++++++++++------------------------------------- utils.py | 39 +++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 55 deletions(-) diff --git a/install.py b/install.py index 10d290a..96abded 100755 --- a/install.py +++ b/install.py @@ -5,14 +5,13 @@ import time import atexit import shutil -import struct import tarfile import os.path import subprocess from collections import OrderedDict from ntfsea import ntfsea, lxattrb, stmode -from utils import Fore, ProgressFileObject, parse_image_arg, probe_wsl, get_label, show_cursor, hide_cursor, draw_progress, clear_progress, escape_ntfs_invalid +from utils import * try: import PySquashfsImage @@ -45,39 +44,31 @@ basedir, lxpath = probe_wsl() +uid = 0 +gid = 0 user = '' isroot = False homedir = '' homedirw = '' -# somewhat a major issue, stdout and stderr can't be redirected, so this script can't monitor the output -# of any of the launched commands. it can, however, receive the exit status, so that's something, I guess. -# ref: https://github.com/Microsoft/BashOnWindows/issues/2 - try: - subprocess.check_call(['cmd', '/C', lxpath + '\\bash.exe', '-c', 'echo $HOME > /tmp/.wsl_usr.txt; echo $USER >> /tmp/.wsl_usr.txt']) - out = os.path.join(basedir, 'rootfs/tmp/.wsl_usr.txt') - - if not os.path.isfile(out): - print('%s[!]%s Failed to get home directory of default user in WSL: Output file %s%s%s not present.' % (Fore.RED, Fore.RESET, Fore.BLUE, out, Fore.RESET)) - sys.exit(-1) + uid, gid, user = get_lxss_user() - with open(out) as f: - homedir = f.readline().strip() - homedirw = os.path.join(basedir, homedir.lstrip('/')) + if uid == 0: + isroot = True + homedir = '/root' + else: + homedir = '/home/' + user - if len(homedir) == 0 or not os.path.isdir(homedirw): - print('%s[!]%s Failed to get home directory of default user in WSL: Returned path %s%s%s is not valid.' % (Fore.RED, Fore.RESET, Fore.BLUE, homedirw, Fore.RESET)) - sys.exit(-1) + homedirw = os.path.join(basedir, homedir.lstrip('/')) - user = f.readline().strip() - isroot = user == 'root' + if len(homedir) == 0 or not os.path.isdir(homedirw): + print('%s[!]%s Failed to get home directory of default user in WSL: Returned path %s%s%s is not valid.' % (Fore.RED, Fore.RESET, Fore.BLUE, homedirw, Fore.RESET)) + sys.exit(-1) print('%s[*]%s Default user is %s%s%s at %s%s%s.' % (Fore.GREEN, Fore.RESET, Fore.YELLOW, user, Fore.RESET, Fore.BLUE, homedir, Fore.RESET)) - os.unlink(out) - -except subprocess.CalledProcessError as err: +except BaseException as err: print('%s[!]%s Failed to get home directory of default user in WSL: %s' % (Fore.RED, Fore.RESET, err)) sys.exit(-1) @@ -456,54 +447,32 @@ def retry_rw(operation, name, exc): print('%s[*]%s Switching default user to %sroot%s...' % (Fore.GREEN, Fore.RESET, Fore.YELLOW, Fore.RESET)) try: - subprocess.check_output(['cmd', '/C', lxpath + '\\lxrun.exe', '/setdefaultuser', 'root']) + set_lxss_user(0, 0, 'root') - except subprocess.CalledProcessError as err: + except BaseException as err: print('%s[!]%s Failed to switch default user in WSL: %s' % (Fore.RED, Fore.RESET, err)) sys.exit(-1) - try: - subprocess.check_call(['cmd', '/C', lxpath + '\\bash.exe', '-c', - 'echo $HOME > /tmp/.wsl_usr.txt; echo $USER >> /tmp/.wsl_usr.txt']) - out = os.path.join(basedir, 'rootfs/tmp/.wsl_usr.txt') - - if not os.path.isfile(out): - print('%s[!]%s Failed to get home directory of default user in WSL: Output file %s%s%s not present.' % (Fore.RED, Fore.RESET, Fore.BLUE, out, Fore.RESET)) - sys.exit(-1) - - with open(out) as f: - homedir = f.readline().strip() - homedirw = os.path.join(basedir, homedir.lstrip('/')) - - if len(homedir) == 0 or not os.path.isdir(homedirw): - print('%s[!]%s Failed to get home directory of default user in WSL: Returned path %s%s%s is not valid.' % (Fore.RED, Fore.RESET, Fore.BLUE, homedirw, Fore.RESET)) - sys.exit(-1) - - user2 = f.readline().strip() - - if user2 != 'root': - print('%s[!]%s Failed to switch default user to %sroot%s.' % (Fore.RED, Fore.RESET, Fore.YELLOW, Fore.RESET)) - sys.exit(-1) + homedir = '/root' + homedirw = os.path.join(basedir, homedir.lstrip('/')) - os.unlink(out) - - except subprocess.CalledProcessError as err: - print('%s[!]%s Failed to get home directory of default user in WSL: %s' % (Fore.RED, Fore.RESET, err)) + if not os.path.isdir(homedirw): + print('%s[!]%s Failed to get home directory of default user in WSL: Returned path %s%s%s is not valid.' % (Fore.RED, Fore.RESET, Fore.BLUE, homedirw, Fore.RESET)) sys.exit(-1) # since we switched to root, switch back to regular user on exit - def switch_user_back(user): + def switch_user_back(uid, gid, user): print('%s[*]%s Switching default user back to %s%s%s...' % (Fore.GREEN, Fore.RESET, Fore.YELLOW, user, Fore.RESET)) try: - subprocess.check_output(['cmd', '/C', lxpath + '\\lxrun.exe', '/setdefaultuser', user]) + set_lxss_user(uid, gid, user) - except subprocess.CalledProcessError as err: + except BaseException as err: print('%s[!]%s Failed to switch default user in WSL: %s' % (Fore.RED, Fore.RESET, err)) sys.exit(-1) - atexit.register(switch_user_back, user) + atexit.register(switch_user_back, uid, gid, user) # run post-install hooks, if any diff --git a/utils.py b/utils.py index 5f8022a..e15ffbe 100755 --- a/utils.py +++ b/utils.py @@ -5,6 +5,7 @@ import sys import glob import time +import winreg # try to get colors, but don't make it a nuisance by requiring dependencies @@ -445,3 +446,41 @@ def clear_progress(): sys.stdout.write('\033]9;4;0\033\\\033[39m') sys.stdout.flush() + + +# functions to interact with the registry + +def get_lxss_user(): + """ + Gets the active user inside WSL. + + :return: Tuple of UID, GID and the name of the user. + """ + + with winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Software\\Microsoft\\Windows\\CurrentVersion\\Lxss', access = winreg.KEY_READ | winreg.KEY_WOW64_64KEY) as lxreg: + uid, uid_type = winreg.QueryValueEx(lxreg, 'DefaultUid') + gid, gid_type = winreg.QueryValueEx(lxreg, 'DefaultGid') + user, user_type = winreg.QueryValueEx(lxreg, 'DefaultUsername') + + if uid_type != winreg.REG_DWORD or gid_type != winreg.REG_DWORD: + raise WindowsError('DefaultUid or DefaultGid is not DWORD.') + + if user_type != winreg.REG_SZ: + raise WindowsError('DefaultUsername is not string.') + + return uid, gid, user + + +def set_lxss_user(uid, gid, user): + """ + Switches the active user inside WSL to the requested one. + + :param uid: UID of the new user. + :param gid: GID of the new user. + :param user: Name of the new user. + """ + + with winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Software\\Microsoft\\Windows\\CurrentVersion\\Lxss', access = winreg.KEY_WRITE | winreg.KEY_WOW64_64KEY) as lxreg: + winreg.SetValueEx(lxreg, 'DefaultUid', 0, winreg.REG_DWORD, uid) + winreg.SetValueEx(lxreg, 'DefaultGid', 0, winreg.REG_DWORD, gid) + winreg.SetValueEx(lxreg, 'DefaultUsername', 0, winreg.REG_SZ, user)