Skip to content

Commit

Permalink
User switching now happens directly, without involving WSL through lx…
Browse files Browse the repository at this point in the history
…run. This way broken installations can be repaired without failing at the 'Probing the Linux subsystem' step.
  • Loading branch information
RoliSoft committed Oct 22, 2016
1 parent 68ff460 commit faac0a6
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 55 deletions.
79 changes: 24 additions & 55 deletions install.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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

Expand Down
39 changes: 39 additions & 0 deletions utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)

0 comments on commit faac0a6

Please sign in to comment.