在 Windows 上,是不是可以以不同的用户身份运行单个 goroutine?

Posted

技术标签:

【中文标题】在 Windows 上,是不是可以以不同的用户身份运行单个 goroutine?【英文标题】:On windows, is it possible to run a single goroutine as a different user?在 Windows 上,是否可以以不同的用户身份运行单个 goroutine? 【发布时间】:2014-09-30 14:23:20 【问题描述】:

如何将 goroutine 的运行委托给 Windows 上的另一个非管理员帐户?我看到你可以使用syscall.Setuid() 在Linux 上执行此操作。我看不到如何使用 windows syscall 包在 Windows 上执行此操作。我希望能够在程序运行时设置 goroutine 运行的帐户。这可能吗?

背景知识:- 我想切换运行 goroutine 的用户,这样我就可以在使用 go-oci8 时更改在数据库连接期间传递给 Oracle 的 OS 用户(请参阅我的其他 @ 987654322@)。我需要连接到数据库,它使用登录用户(操作系统用户)作为安全性的一部分。在java中,我可以在连接设置期间更改环境变量(或者如果只为单个用户连接,则轻弹用户名环境变量)。

我有用户数据库用户名(这与操作系统用户名匹配),我得到了数据库用户密码。我没有用户的 windows 登录密码。我希望能够以与我强调的 Linux 端口绑定示例类似的方式,以管理员身份运行的主 go 程序将运行 goroutine 委托给所需的 windows 用户。将 Oracle 登录名更改为不使用 OS 用户不是一个选项,因此如果我无法解决,它将返回 Java :-(。

【问题讨论】:

嗯,好像linux也有problems。我会尝试在流程级别解决这个问题... 但也许this 包可能会感兴趣。 Linux 上唯一真正的解决方案是每次重新编译程序时使用sudo setcap 'cap_net_bind_service=+ep' app,在 Windows 上我不知道。 您要究竟做什么?你只需要绑定一个你链接的讨论中的端口吗? @JimB 我已经更新了问题以解释为什么我需要委派 【参考方案1】:

理论上,不,这是不可能的,因为在 Linux 和 Windows 上,用户身份的概念只存在于操作系统级别的线程中,而 goroutines 不是操作系统线程——相反,它们非常轻量级- 权重实体,由 Go 调度程序(内置在可执行文件中的 Go 运行时的一部分)映射到真实的 OS 线程,并且在其生命周期内,goroutine 可能在不同的时间在不同的 OS 线程上执行。

但是对于您的情况,存在一种“退出舱口”,最初旨在帮助调用C 代码:runtime.LockOSThread()。一旦一个 goroutine 调用了这个函数,它就会被困在它当前运行的线程上,并且无论如何都不会被安排在另一个线程上调用,直到 goroutine 退出或调用 runtime.UnlockOSThread()

你可以这样使用:

go func() 
  runtime.LockOSThread()
  defer runtime.UnlockOSThread()
  impersonate() // acquires and assumes some other credentials
  ...

那个虚构的impersonate() 函数的实现超出了这个问题的范围;您可以使用 syscall 包调用任何 Win32 API 函数 — 有关示例,请参见标准 Go 库。


请注意,在实际场景中调用 runtime.LockOSThread() 会导致将整个操作系统线程专用于一个 goroutine(而通常它们中的很多只在一个 goroutine 上运行)所以如果你打算生成很多此类锁定到 OS 线程的 goroutine 已准备好处理增加的 OS 资源使用情况。

更新:a working example 在 Windows XP Pro SP3 32 位 Go 1.2.1/i386 上测试。

它硬编码由密码“foo”标识的用户“foo”。要在 Windows 上快速创建用户,请执行

net user foo * /ADD

并在出现提示时输入密码两次。

【讨论】:

还要注意,如果 OP 希望所有东西都在同一个帐户下运行,那么任何产生 goroutines 的东西(很多东西都会做,比如 HTTP 服务器)将立即安排在原始帐户下的线程上。 @kostix 你能提供一个win32 API函数调用的例子吗?如果我无法在本机 go 代码中设置帐户,那么第三方 windows api 调用听起来是下一个最佳选择。我很高兴将 go-routine 锁定到线程,因为作为替代 Windows 用户帐户进行的调用非常快。 @JimboJambo,我觉得很冒险并写了一个工作示例——请参阅更新后的答案。 @kostix 很好的例子。谢谢。是否可以在没有用户登录密码的情况下进行委托?我希望从管理员帐户委托给用户帐户,而不需要 Windows 登录密码 @JimboJambo,恐怕没有办法。至少我什么都不知道。使用标签 [winapi] 在 SO 中搜索单词 impersonate 以获取概览(不,您不是第一个提出此类请求的人;例如,请参阅 this)。许多人提到了一个低级无证 ZwCreateToken() 函数,但我没有看到任何用法示例,因此无法评论它。【参考方案2】:

Goroutines 是绿色线程,可以随意映射到各种操作系统线程。因此,您最初的假设(您可以在 linux 上使用简单的 syscall.Setuid() 来做到这一点)也可能是错误的。我认为你需要在一个完全独立的进程中运行才能获得你想要的权限限制。

【讨论】:

runtime.LockOSThread 用于将 goroutine 锁定到 OS 线程,但是是的,有更好/更安全的权限分离方法。 @JimB 除非您控制 goroutine,否则它将无法工作,如果是 http 服务器,则运行时管理它。 @OneOfOne:您绝对可以控制绑定侦听端口的 goroutine,这就是 OP 在链接讨论中所指的内容。但是,如果您需要 所有 生成的 goroutine 具有相同的 UID,那么您是对的。

以上是关于在 Windows 上,是不是可以以不同的用户身份运行单个 goroutine?的主要内容,如果未能解决你的问题,请参考以下文章

如何以与 Windows 服务不同的用户身份运行进程

Windows 身份验证 - 如何使用代码拒绝用户

在 Android 上使用 facebook SDK 会给出“用户以不同的 Facebook 用户身份登录”。错误

无法以不同用户身份运行 C# 进程

您可以以编程方式打开“以不同用户身份运行”对话框吗?

当 Windows 用户不是管理员时,ReadXml 的不同行为