1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
# -*- coding: utf-8 -*-
"""
The ``EndUser`` object the object that represents the user account owned by the human user of the system. It is possible to run subuser using a different user account, in order to isolate root from the end user's user account.
"""
#external imports
import getpass
import os
import sys
import pwd
import subprocess
#internal imports
from subuserlib import test
from subuserlib import paths
from subuserlib.classes.userOwnedObject import UserOwnedObject
def timeit(func):
import functools,time
@functools.wraps(func)
def newfunc(*args, **kwargs):
startTime = time.time()
ret = func(*args, **kwargs)
elapsedTime = time.time() - startTime
print('function [{}] finished in {} ms'.format(
func.__name__, int(elapsedTime * 1000)))
return ret
return newfunc
class EndUser(UserOwnedObject,object):
def __init__(self,user,name=None):
UserOwnedObject.__init__(self,user)
self.proxiedByOtherUser = False
self.sudo = False
self.name = name
try:
self.name = self.user.config["user"]
self.proxiedByOtherUser = True
except KeyError:
try:
self.name = os.environ["SUDO_USER"]
self.sudo = True
self.proxiedByOtherUser = True
except KeyError:
try:
self.name = getpass.getuser()
except KeyError:
# We use a broken setup when generating documentation...
self.name = "I have no name!"
self.uid = 1000
self.gid = 1000
if not test.testing:
if self.sudo:
self.uid = int(os.environ.get('SUDO_UID'))
self.gid = int(os.environ.get('SUDO_GID'))
else:
try:
self.uid = pwd.getpwnam(self.name)[2]
self.gid = pwd.getpwnam(self.name)[3]
except KeyError:
pass
if not self.uid == 0:
self.homeDir = os.path.join("/home/",self.name)
else:
self.homeDir = "/root/"
def chown(self,path):
"""
Make this user own the given file if subuser is running as root.
"""
if self.proxiedByOtherUser:
os.chown(path,self.uid,self.gid)
#Thanks https://stackoverflow.com/questions/25791311/creating-a-file-with-python-using-sudo-makes-its-owner-root
def create_file(self,path):
#create containing folder
directory,_ = os.path.split(path)
self.makedirs(directory)
#create file normally
open(path, 'a').close()
# then fix the ownership
self.chown(path)
def get_file(self,path, mode="a+"):
"""Create a file if it does not exists, fix ownership and return it open"""
self.create_file(path)
# open the file and return it
return open(path, mode)
def makedirs(self,path):
"""
Create directory + parents, if the directory does not yet exist. Newly created directories will be owned by the user.
"""
# Taken from https://stackoverflow.com/questions/3167154/how-to-split-a-dos-path-into-its-components-in-python
folders = []
path = os.path.realpath(path)
while 1:
path, folder = os.path.split(path)
if folder:
folders.append(folder)
else:
if path:
folders.append(path)
break
pathBeingBuilt = "/"
for folder in reversed(folders):
pathBeingBuilt = os.path.join(pathBeingBuilt,folder)
if not os.path.exists(pathBeingBuilt):
self.mkdir(pathBeingBuilt)
def mkdir(self,path):
os.mkdir(path)
self.chown(path)
def getSudoArgs(self):
if self.proxiedByOtherUser:
return ["sudo","--user",self.name]
else:
return []
def call(self,command,cwd=None):
process = subprocess.Popen(self.getSudoArgs()+command,cwd=cwd)
(stdout,stderr) = process.communicate()
return process.returncode
#@timeit
def callCollectOutput(self,args,cwd=None):
"""
Run the command and return a tuple with: (returncode,the output to stdout as a string,stderr as a string).
"""
args = self.getSudoArgs() + args
#print(args)
process = subprocess.Popen(args,stdout=subprocess.PIPE,stderr=subprocess.PIPE,cwd=cwd)
(stdout,stderr) = process.communicate()
return (process.returncode,stdout.decode("utf-8"),stderr.decode("utf-8"))
def Popen(self,command,*args,**kwargs):
return subprocess.Popen(self.getSudoArgs()+command,*args,**kwargs)
def runEditor(self,filePath):
"""
Launch a file editor and edit the given filePath.
"""
try:
editor = os.environ["EDITOR"]
except KeyError:
editor = "/usr/bin/nano"
def actuallyRunEditor(editor,filePath):
try:
self.call([editor,filePath])
except FileNotFoundError:
if test.testing:
return
editor = input(editor+" not found. Please enter the name of your favorite editor:")
actuallyRunEditor(editor,filePath)
actuallyRunEditor(editor,filePath)
|