From 164c575f2a0da53a6bd6a95dd4d33082362f02b8 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Fri, 3 Jul 2020 15:35:32 +1200 Subject: [PATCH] use snapd apis to check for a user and (minimally) handle a managed system with no owner --- console_conf/controllers/identity.py | 78 ++++++++++++++++------------ console_conf/ui/views/login.py | 16 ++++-- 2 files changed, 57 insertions(+), 37 deletions(-) diff --git a/console_conf/controllers/identity.py b/console_conf/controllers/identity.py index a97ae669..ed0e085c 100644 --- a/console_conf/controllers/identity.py +++ b/console_conf/controllers/identity.py @@ -16,11 +16,13 @@ import json import logging import os +import pwd import shlex import sys from subiquitycore.controller import BaseController from subiquitycore.ssh import host_key_info, get_ips_standalone +from subiquitycore.snapd import SnapdConnection from subiquitycore.utils import disable_console_conf, run_command from console_conf.ui.views import IdentityView, LoginView @@ -50,24 +52,31 @@ def get_core_version(): return version -def get_device_owner(): - """ Check if device is owned """ +def get_managed(): + """ Check if device is managed """ + con = SnapdConnection('', '/run/snapd.socket') + return con.get('v2/system-info').json()['result']['managed'] - # TODO: use proper snap APIs. + +def get_realname(username): try: - extrausers_fp = open('/var/lib/extrausers/passwd', 'r') - except FileNotFoundError: - return None - with extrausers_fp: - passwd_line = extrausers_fp.readline() - if passwd_line and len(passwd_line) > 0: - passwd = passwd_line.split(':') - result = { - 'realname': passwd[4].split(',')[0], - 'username': passwd[0], - 'homedir': passwd[5], + info = pwd.getpwnam(username) + except KeyError: + return '' + return info.pw_gecos.split(',', 1)[0] + + +def get_device_owner(): + """ Get device owner, if any """ + con = SnapdConnection('', '/run/snapd.socket') + for user in con.get('v2/users').json()['result']: + user = user['email'].split('@')[0] + if os.path.isdir('/home/' + user): + return { + 'username': user, + 'realname': get_realname(user), + 'homedir': '/home/' + user, } - return result return None @@ -111,17 +120,21 @@ def write_login_details(fp, username, ips): def write_login_details_standalone(): owner = get_device_owner() - if owner is None: - print("No device owner details found.") - return 0 ips = get_ips_standalone() if len(ips) == 0: - tty_name = os.ttyname(0)[5:] - version = get_core_version() or "16" - print(login_details_tmpl_no_ip.format(tty_name=tty_name, - version=version)) - return 2 - write_login_details(sys.stdout, owner['username'], ips) + if owner is None: + print("device managed without user") + return 2 + else: + tty_name = os.ttyname(0)[5:] + version = get_core_version() or "16" + print(login_details_tmpl_no_ip.format( + tty_name=tty_name, version=version)) + return 2 + if owner is None: + print("device managed without user @ {}".format(', '.join(ips))) + else: + write_login_details(sys.stdout, owner['username'], ips) return 0 @@ -133,14 +146,15 @@ class IdentityController(BaseController): def start_ui(self): self.ui.set_body(IdentityView(self.model, self)) - device_owner = get_device_owner() - if device_owner is not None: - self.model.add_user(device_owner) - key_file = os.path.join(device_owner['homedir'], - ".ssh/authorized_keys") - self.model.user.fingerprints = ( - run_command(['ssh-keygen', '-lf', - key_file]).stdout.replace('\r', '').splitlines()) + if get_managed(): + device_owner = get_device_owner() + if device_owner: + self.model.add_user(device_owner) + key_file = os.path.join(device_owner['homedir'], + ".ssh/authorized_keys") + cp = run_command(['ssh-keygen', '-lf', key_file]) + self.model.user.fingerprints = ( + cp.stdout.replace('\r', '').splitlines()) self.login() def identity_done(self, email): diff --git a/console_conf/ui/views/login.py b/console_conf/ui/views/login.py index 8de40b3a..e9de4512 100644 --- a/console_conf/ui/views/login.py +++ b/console_conf/ui/views/login.py @@ -57,6 +57,17 @@ class LoginView(BaseView): ] def _build_model_inputs(self): + user = self.model.user + ips = [] + for dev in self.netdevs: + for addr in dev.actual_global_ip_addresses: + ips.append(addr) + + if not user: + sl = [] + sl.append(Text("no owner")) + return sl + local_tpl = ( "This device is registered to {realname}.") @@ -67,17 +78,12 @@ class LoginView(BaseView): "device via SSH:") sl = [] - user = self.model.user login_info = { 'realname': user.realname, 'username': user.username, } login_text = local_tpl.format(**login_info) login_text += remote_tpl.format(**login_info) - ips = [] - for dev in self.netdevs: - for addr in dev.actual_global_ip_addresses: - ips.append(addr) sl += [Text(login_text), Padding.line_break("")] for ip in ips: