Windows服务器应用程序的fork/chroot等效功能

5
我已经在Linux上用C语言写了一个小型的自定义Web服务器应用程序。当该应用程序接收到请求时,它调用fork()方法并在单独的进程中处理请求,该进程被chroot到特定目录中,其中包含我想要公开的文件。
我想将该应用程序移植到Windows平台,但是在该平台上既没有fork()方法也没有chroot()方法,并且似乎也没有直接的等价物。你能指导我提供这个功能在Windows下的简单(最好是书写良好)示例代码吗?我的C语言不是很好,所以越简单越好。

到目前为止的答案表明,没有简单的替代fork()函数的方法。我很乐意考虑使用单独的线程而不是fork()一个新进程,但仍希望有一个代码示例。有许多在Windows上运行的Web服务器(例如Apache),它们必须解决fork()和chroot()问题,我可以接受一个简要概述通常采用的方法以及指向Apache(或其他)源代码相关部分的链接。 - codebox
根据您的评论,我建议您不要基于Cygwin示例源代码编写代码,而是使用Apache Portable Runtime库来为您处理细节。 - Michael Dillon
我也认为你应该使用一些库。另外请参考以下链接:http://www.gnu.org/software/libmicrohttpd/ - 一个支持Windows和Unix的HTTP服务器库。用于在程序中嵌入Web服务器功能。http://abyss.sourceforge.net/ - 适用于win/unix的Web服务器此外,您可以忘记线程和进程,使用非阻塞IO。这样,您只需要一个进程,而不是在列表或数组中跟踪连接。例如:http://www.cubicsky.com/files/shinyhttpd-0.1.3-src.tar.gz - Prof. Falken
我最终选择使用线程来处理这个问题,而不是fork - 不幸的是,由于这个原因,我不得不重新设计一些我的现有代码以使其线程安全,而fork则不需要。 对于问题中的chroot部分,我想我将不得不自己检查文件路径,这看起来像是检测试图通过在URL中插入'../..'来走上目录树的尝试的一个好方法http://msdn.microsoft.com/en-us/library/bb773569(VS.85).aspx - codebox
6个回答

9
首先,Windows中与chroot等效的是RUNAS,相关文档在这里。如果你需要从程序中执行此操作,则可以研究这个C++源代码,以了解如何使用Windows API。虽然它不完全相同于chroot(),但Windows用户使用它创建类似于chroot jail的东西,通过创建一个具有极限权限的用户,并仅为该用户提供应用程序文件夹的读取权限和一个数据文件夹的写入权限。
你可能不想在Windows上完全模拟fork(),因为这听起来并不需要那么远。要了解创建进程的Windows API及其与fork()的区别,请查看Mr. Peabody解释fork()。而Cygwin的fork实现则展示了当前技术的最新状态。
关于CreateProcess()CreateThread(),Microsoft的文档是查找更多信息的地方。
最后,如果你不想学习所有琐碎的平台细节,只需编写可在Windows和Unix上运行的便携式程序,为什么不直接使用Apache Portable Runtime库本身呢?这里有一些关于进程创建的文档和示例代码,用C语言编写,来创建一个新的进程。

1
这不是 chroot()chroot 改变的是你的根目录,而不是你所识别的用户。 - Hasturkun
4
您说得对,这不是chroot(),因为Windows没有chroot(),但RUNAS.EXE是Windows用户用来创建类似于UNIX chroot监狱的工具。 - Michael Dillon
4
RUNAS不同于chroot监狱。 - Roger Pate
关于Apache可移植运行库,有一个名为apr_proc_fork的函数,并附有以下说明:这是APR目前唯一的非可移植调用。此函数执行标准Unix fork操作。 我理解这意味着除*nix之外,在APR中没有fork()函数。如果我理解有误,请指出。 - Piotr Dobrogost

3
在Windows上不存在fork()函数。你需要调用CreateProcess()函数,这将启动一个独立的进程(大多等同于调用fork()然后立即为生成的进程调用exec()),并以某种方式传递参数。由于你似乎已经有了要处理的所有数据所在的专用目录,因此你可以利用CreateProcess()lpCurrentDirectory参数——只需将之前用chroot()设置的目录路径传递给它即可。

1
请注意,lpCurrentDirectory 对应的是 chdir() 而不是 chroot()。 - Baffe Boyois
谢谢,但这不是我需要的正是因为使用chroot的主要原因是安全性(防止某人在请求URL中使用../..来访问文件系统中的其他文件),而设置当前目录无法提供此安全保障。另外,我有很多在内存中的值需要由分叉进程使用,据我所知通过exec传递这些值的唯一方法是作为命令行参数,而我不想那样做... - codebox
2
好的,Windows 没有像 fork() 这样可以复制进程的功能。无论如何,您都必须使用某种形式的 IPC,因此通过命令行或通过临时文件传递可能是最简单的方法。至于 chroot(),您可以执行以下操作:为运行工作进程创建一个单独的帐户,该帐户除了临时文件夹之外没有任何权限,并在该帐户下运行工作进程。 - sharptooth
在Windows上创建进程是一项昂贵的操作,相比之下fork()或vfork()更加高效,这就是为什么Microsoft推荐使用线程的原因。 - Chris J
@sharptooth - 最终取决于OP想要实现什么。如果这只是一个供OP使用的个人项目,那么CreateProcess可能很好。但是,如果这将被稍微频繁地使用,他最好考虑采用Windows多线程路线。如果这是更复杂的学习练习,那么我建议学习CreateThread而不是尝试模拟fork()。 - Chris J
显示剩余2条评论

2

最简单的方法是使用Windows下的免费Unix仿真层Cygwin。下载并安装完整的开发环境(在安装程序中选择)。如果你很幸运,你可以直接编译你的程序而不需要做任何修改。

当然,这种方法也有缺点,有些人可能会认为这是“作弊”,但你要求的是最简单的解决方案。


1
我的理解是,Cygwin的chroot监狱并不完美。非Cygwin编译的任务可能会逃脱出去。 - Sanjaya R
Sanjaya,你可能是正确的,但对于大多数情况,它应该可以工作。 - Prof. Falken

1

如果不使用兼容性框架(Interix、Cygwin等),则需要使用Windows范例来完成这种操作。

在UNIX系统中,fork/vfork是一种廉价的操作,因此与多线程相比,它经常被使用。而Windows中的等效操作CreateProcess()则相对昂贵,因此您应该考虑使用线程,使用CreateThread()创建线程。有很多示例代码可以使用CreateThread()。

关于chroot(),Windows没有这个概念。有一些库声称可以模拟您所需的功能。但是这取决于您为什么要使用chroot。

根据评论,如果只是为了防止人们使用../../../../(等)向上跳转,则chroot可以完成任务,但它不能替代首先解析输入并确保其合理:即,如果指定了太多的父级目录,则将用户锁定到已知的根目录。Apache几乎肯定会执行此操作,因为我从未必须为Apache创建chroot()环境...


0

在Windows上,使用fork/chroot根本不是做事情的方式。如果您关心子进程中的安全性,可能需要使用某种形式的虚拟化或沙盒技术。通过某种形式的RPC解决方案可以传递复杂信息到子进程。

听起来好像您已经按照Unix的方式设计了应用程序,现在想在Windows上运行而不必更改任何内容。在这种情况下,您可能需要考虑使用Cygwin,但我不确定Cygwin如何模拟chroot


0

考虑使用SUA(也称为Windows Services for Unix)。它几乎拥有你需要移植应用程序的一切。

man chroot(interix)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接