作者:lee某某 | 来源:互联网 | 2022-12-09 17:50
我正在寻找一种方法来运行部分python代码/函数作为Linux中的不同用户运行,而不是生成另一个脚本.
例如:
def function1(args):
# stuffs
def function2():
# stuffs
我想通过传递几个参数来调用函数function1
,function2
并且function1
应该接受这些参数并将其作为不同的用户执行并返回结果.因为我必须在整个执行期间调用一些东西,所以我不想为小块代码创建多个脚本.基本上我试图在函数中连接数据库function1
(数据库连接只能作为特定用户完成)并运行查询并获得结果.
1> zwer..:
这比你想象的要困难一些.首先,Python提供os.setuid()
并os.setguid()
更改正在运行的脚本的当前用户/组,您可以创建一个上下文管理器来为您进行出价并自动恢复为当前正在执行的用户:
import os
class UnixUser(object):
def __init__(self, uid, gid=None):
self.uid = uid
self.gid = gid
def __enter__(self):
self.cache = os.getuid(), os.getgid() # cache the current UID and GID
if self.gid is not None: # GID change requested as well
os.setgid(self.gid)
os.setuid(self.uid) # set the UID for the code within the `with` block
def __exit__(self, exc_type, exc_val, exc_tb):
# optionally, deal with the exception
os.setuid(self.cache[0]) # revert back to the original UID
os.setgid(self.cache[1]) # revert back to the original GID
并测试它:
def test():
print("Current UID: {}".format(os.getuid())) # prints the UID of the executing user
test() # executes as the current user
with UnixUser(105):
test() # executes as the user with UID: 105
您甚至可以创建一个整洁的装饰器来选择某些功能应该始终作为另一个用户执行:
def as_unix_user(uid, gid=None): # optional group
def wrapper(func):
def wrapped(*args, **kwargs):
with UnixUser(uid, gid):
return func(*args, **kwargs) # execute the function
return wrapped
return wrapper
def test1():
print("Current UID: {}".format(os.getuid())) # prints the UID of the executing user
@as_unix_user(105)
def test2():
print("Current UID: {}".format(os.getuid())) # prints the UID of the executing user
test1() # executes as the current user
test2() # executes as the user with UID: 105
踢球者?在不是线程安全的旁边,只有当前用户和要执行该功能的用户都具有CAP_SETUID
和可选的功能时,它才会起作用CAP_SETGID
.
只有一个具有这些功能的用户运行主脚本然后在必要时进行分叉,仅在分叉进程上更改UID/GID,您就可以逃脱:
import os
def as_unix_user(uid, gid=None): # optional group
def wrapper(func):
def wrapped(*args, **kwargs):
pid = os.fork()
if pid == 0: # we're in the forked process
if gid is not None: # GID change requested as well
os.setgid(gid)
os.setuid(uid) # set the UID for the code within the `with` block
func(*args, **kwargs) # execute the function
os._exit(0) # exit the child process
return wrapped
return wrapper
def test1():
print("Current UID: {}".format(os.getuid())) # prints the UID of the executing user
@as_unix_user(105)
def test2():
print("Current UID: {}".format(os.getuid())) # prints the UID of the executing user
test1() # executes as the current user
test2() # executes as the user with UID: 105
踢球者在这?您没有从分叉函数中获取返回数据.如果需要,您必须将其传回父进程,然后在父进程中等待它完成.您还需要选择一种格式来在进程之间传递数据(如果足够简单,我建议使用JSON或者返回本机pickle
)...
那时,你已经完成了subprocess
模块正在做的事情的一半,所以你也可以将你的函数作为子进程启动并完成它.如果你必须经历这样的箍以达到你想要的结果,那么你原来的设计很可能是错误的.在您的情况下 - 为什么不直接向当前用户提供访问数据库的权限?用户需要具备切换到另一个用户的能力,这样你就不会从中获得任何安全性 - 你只会使你的生活变得复杂.