diff --git a/rattail/commands.py b/rattail/commands.py index 811df70f36a204313e18ee9e73f697215c5bf54b..8ebeb2d5d4e33d6ffd84232eed2a849633ea6783 100644 --- a/rattail/commands.py +++ b/rattail/commands.py @@ -223,6 +223,34 @@ class MakeConfigCommand(commands.Subcommand): shutil.copyfile(src, dest) +class MakeUserCommand(commands.Subcommand): + """ + Creates a system user for Rattail. + """ + + name = 'make-user' + description = "Create a system user account for Rattail" + + def run(self, args): + from getpass import getpass + from rattail.win32 import users + + if users.user_exists('rattail'): + sys.stderr.write("User already exists: rattail\n") + sys.exit(1) + + try: + password = None + while not password: + password = getpass("Enter a password: ").strip() + except KeyboardInterrupt: + sys.stderr.write("Operation canceled by user.") + sys.exit(2) + + users.create_rattail_user(password) + sys.stdout.write("Created user: rattail\n") + + class PalmCommand(commands.Subcommand): """ Manages registration for the HotSync Manager conduit; called as:: diff --git a/rattail/win32/users.py b/rattail/win32/users.py new file mode 100644 index 0000000000000000000000000000000000000000..f463cb1c65c99dae9d104ba95bdf71c6e993a3af --- /dev/null +++ b/rattail/win32/users.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +################################################################################ +# +# Rattail -- Retail Software Framework +# Copyright © 2010-2012 Lance Edgar +# +# This file is part of Rattail. +# +# Rattail is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for +# more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Rattail. If not, see . +# +################################################################################ + +""" +``rattail.win32.users`` -- Windows User Utilities +""" + +import socket +import logging + +import win32api +import win32con +import win32net +import win32netcon +import pywintypes +import winerror + + +log = logging.getLogger(__name__) + + +def create_rattail_user(password): + """ + Create a system user account for Rattail. + """ + + if user_exists('rattail'): + log.warning("create_rattail_user: user 'rattail' already exists") + return False + + win32net.NetUserAdd(None, 2, { + 'name': 'rattail', + 'password': password, + 'priv': win32netcon.USER_PRIV_USER, + 'comment': "System user account for Rattail applications", + 'flags': (win32netcon.UF_NORMAL_ACCOUNT + | win32netcon.UF_PASSWD_CANT_CHANGE + | win32netcon.UF_DONT_EXPIRE_PASSWD), + 'full_name': "Rattail User", + }) + + win32net.NetLocalGroupAddMembers(None, 'Users', 3, [ + {'domainandname': r'{0}\rattail'.format(socket.gethostname())}]) + + hide_user_account('rattail') + return True + + +def hide_user_account(username): + """ + Hide a user account from the Welcome screen. + + This also hides it from the User Accounts control panel applet. + """ + + key = win32api.RegOpenKeyEx( + win32con.HKEY_LOCAL_MACHINE, + r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList', + 0, win32con.KEY_ALL_ACCESS) + + win32api.RegSetValueEx(key, username, 0, win32con.REG_DWORD, 0) + win32api.RegCloseKey(key) + + +def user_exists(username): + """ + Determine if a system user account already exists. + """ + + # This constant doesn't seem to be importable from anywhere. + NERR_UserNotFound = 2221 + + try: + info = win32net.NetUserGetInfo(None, username, 1) + except pywintypes.error, error: + if error.winerror == NERR_UserNotFound: + return False + raise + return True diff --git a/setup.py b/setup.py index e47ea11c03112bf230a08e1539ad1f18d814e2e8..143fcd2522514fcfb2f9d24c93ae38e89c63ad95 100644 --- a/setup.py +++ b/setup.py @@ -116,6 +116,7 @@ dbsync = rattail.commands:DatabaseSyncCommand filemon = rattail.commands:FileMonitorCommand load-host-data = rattail.commands:LoadHostDataCommand make-config = rattail.commands:MakeConfigCommand +make-user = rattail.commands:MakeUserCommand palm = rattail.commands:PalmCommand purge-batches = rattail.commands:PurgeBatchesCommand