如何将需要root权限的功能添加到Common Lisp库中?

时间:2013-03-29 09:07:40

标签: linux macos unix common-lisp elevated-privileges

原始问题

我正在尝试创建一个Lisp库,除其他外,它可以编辑我的系统的/etc/hosts文件和nginx配置。我面临的问题是,因为我的Lisp图像是一个无特权的用户,我的图书馆不能做这些事情。理想情况下,当需要root权限时,我可以为我的库提供密码,以便暂时提升其访问权限以完成任务。唉,我找不到sudo的任何Common Lisp等价物。有吗?我是以错误的方式接近这个吗?我怎么能解决这个问题呢?

在代码中,我希望能够做的基本上是这样的:

(with-sudo (:username "root" :password (securely-read-line))
  (with-open-file (f "/etc/hosts" :direction :output :if-exists :append)
    (format f "127.0.0.1 mywebsite.local~%")))

澄清

我在OS X上使用SBCL。我正在尝试创建一个基本上是网站快速项目专业化的库。目前,每次在本地计算机上设置新的Web项目时,我都必须编辑遍布系统的配置文件。我想尽可能自动化,我希望能够在我通常打开并连接到单个SBCL实例的SLIME会话中执行此操作。

以下是其他一些注意事项:

  1. 我不希望我的主要SBCL实例setuid'为root
  2. 我不介意产生一个新进程,无论是小型C程序还是SBCL的裸实例,它会加载几行代码然后退出。
  3. 我想尽量保持Lisp与C的比例。
  4. 某些文本编辑器(如TextMate)在访问需要更高权限查看的文件时会提示用户名和密码,并提供相应的访问权限。我想知道如何让我的Lisp库做同样的事情?
  5. 起初我无法让sudo(实际程序本身)在SBCL内工作:

    (inferior-shell:run/ss '("sudo" "ls" ".")) ;; how can I pass sudo a password?

    现在看来可以使用sudo的{​​{1}}选项(谢谢JustAnotherCurious)。我想我可能会走这条路;这绝对是我现在所倾向的。

  6. 无论如何,谢谢大家!我从你们所有人那里学到很多东西。

4 个答案:

答案 0 :(得分:5)

如果您的进程需要root访问权限,则需要最初以root身份启动Lisp进程。通常不可能像回顾一样运行非根进程。

幸运的是,Unix有一种机制允许进程在运行时在根权限和非root权限之间切换。该机制称为有效用户ID。以root身份运行的进程可以使用seteuid系统调用切换到非root有效uid,也可以通过这种方式切换回“正在”root。

当然,如果您以root身份启动Lisp进程,那么该进程可以完全控制计算机,并且根据您正在处理的数据和计算机,您需要考虑到您打开的可能的安全漏洞那。幸运的是,在Lisp中很难产生缓冲区溢出,所以从这个角度来看,你处于更安全的一面:)

在Common Lisp中对系统调用接口的访问没有标准化,但是大多数实现都有一个系统的本机接口,如果您计划在Linux / Unix上移植程序,也可以使用CFFI基于Lisps。

以下是以root身份运行的SBCL的成绩单,演示seteuid的使用:

CL-USER> (defun write-file-in-filesystem-root ()
           (handler-case
               (with-open-file (f "/only-root-may-write-to-root"
                                  :direction :output
                                  :if-exists :supersede)
                 (write "hello" :stream f))
             (error (e) (format t "error: ~A~%" e))))
WRITE-FILE-IN-FILESYSTEM-ROOT
CL-USER> (sb-posix:seteuid 0)
0
CL-USER> (write-file-in-filesystem-root)
"hello"
CL-USER> (sb-posix:seteuid 1000)
0
CL-USER> (write-file-in-filesystem-root)
error: error opening #P"/only-root-may-write-to-root": Permission denied
NIL
CL-USER> (sb-posix:seteuid 0)
0
CL-USER> (write-file-in-filesystem-root)
"hello"
CL-USER> (delete-file "/only-root-may-write-to-root")
T

如果您只需要访问受保护的文件,如果保持特定的OSX是可接受的,并且您希望用户使用标准身份验证请求者进行身份验证,则可以使用特定于OSX的authopen命令。 / p>

答案 1 :(得分:3)

首先,您不能也不应该违反Linux权限系统。如果有某种方法滥用权限&身份验证系统,这将是一个巨大的安全漏洞:实际上,每个人都有root权限。如果您想要这种不安全感,请返回MSDOS!

然后,您可以配置系统以提供对几乎所有内容的root访问权限。您可以配置sudosuper命令不要求任何密码(我实际上是故意在某些机器上执行此操作,但我确实知道 - 或者可能会被滥用作为安全漏洞)。这意味着信任运行sudo命令的实体(人或程序)。

此外,某些程序(例如/bin/login/usr/bin/sudo/usr/bin/super ....)可以是setuid(另请阅读credentials(7)和{{3你的Common Lisp实现可能为execve(2)setuid(2)系统调用提供了一个包装器(或者你可以编写那个自己调用 C 系统调用的包装器)

但是,您似乎只想将127.0.0.1 mywebsite.local条目添加到/etc/hosts;为什么不能将这样的条目作为先决条件(因此,在安装Common Lisp软件的人工过程中,您需要 - 对于人类系统管理员 - 应该添加这样的条目)。然后,您所要做的就是将mywebsite.local名称传递给您的Common Lisp程序,这应该很容易。

我会警告不要使用用Common Lisp编写的 setuid 二进制程序。因为,除非您采取特殊预防措施,否则大多数Common Lisp二进制文件都包含(间接通过eval)整个Common Lisp编译器。并让root用户访问动态&像Common Lisp这样强大的编译器(例如SBCL)是一个安全漏洞。

如果您坚持从Common Lisp库以编程方式将mywebsite.local添加到/etc/hosts,您可以编写一个小的 C 帮助程序,其可执行程序例如/usr/local/libexec/helperbinary是root- setuid (即你{em>安装时chown root /usr/local/libexec/helperbinary然后chmod u+s /usr/local/libexec/helperbinary,你显然需要root才能运行这些chownchmod),它正是这样做的,只能从你的Common Lisp二进制文件开始 - 通过适当的技巧。在 C 中编写那个微小的帮助程序时要非常小心,例如:阅读setreuid(2),并多次校对 C 代码(您可以轻松地在 setuid 程序中设置安全漏洞)。

答案 2 :(得分:2)

问题在于您没有“提升”访问权限:您从超级用户权限开始并在不再需要时删除它们(您所指的sudo程序标记为{{3}实现这一目标。)

因此,您想要实现的是需要以root身份启动LISP解释器,然后让它分叉另一个解释器进程并让该进程立即删除其超级用户权限。从那时起,非特权进程可以像往常一样运行您的代码,并使用setuid root进入特权进程,例如,写入/etc/hosts

遗憾的是,实施这一点并非易事。

答案 3 :(得分:2)

如果您具有root访问权限的操作仅限于一些小而简单的操作,并且您可以编写一些特定于平台的代码,那么,我认为它会起作用,您可以尝试执行bash(或其他shell)命令代码与sudo -S。

来自sudo man的

The -S (stdin) option causes sudo to read the password from 
the standard input instead of the terminal device. 
The password must be followed by a newline character.

但我认为最好不要做这些事情。