これができる例については、sambaを見てください。sambaデーモンはrootとして実行されますが、フォークして通常のユーザーの資格情報をできるだけ早く引き継ぎます。
Unixシステムには、実際のユーザー/グループIDと実効ユーザー/グループIDの2つの別個の資格情報のセットがあります。実際のセットはあなたが実際に誰であるかを識別し、効果的なセットはあなたがアクセスできるものを定義します。移行中は実際のユーザー/グループIDがrootのままであるため、rootの場合は、有効なuid / gidを自由に変更できます(通常のユーザーを含む)。したがって、単一のプロセスでこれを行う別の方法はseteuid/gid
、必要に応じてさまざまなユーザーの権限を前後に適用するために使用することです。サーバーデーモンがrootとして実行されているか、または持っているCAP_SETUID
場合、これは許可されます。
ただし、気まぐれで有効なuid / gidを切り替える機能があり、アプリケーションが破壊された場合、その破壊によって、たとえば有効なuid / gidが0に戻され、重大なセキュリティの脆弱性が発生する可能性があることに注意してください。これが、実際のユーザーuid/gidを含むすべての特権をできるだけ早く永久に削除することが賢明な理由です。
このため、単一のリスニングソケットをrootとして実行し、次にフォークして、を呼び出して実際のユーザーIDと有効なユーザーIDの両方を変更するのが通常で安全setuid
です。その後、元に戻すことはできません。フォークされたプロセスaccept()
には、フォークであるために編集されたソケットがあります。各プロセスは、不要なファイル記述子を閉じるだけです。ソケットは、反対のプロセスでファイル記述子によって参照されるため、存続します。
自分で個別にアクセス許可を調べて強制することもできますが、これは潜在的にエラーが発生しやすく、多くのエッジケースがあり、うまくいかない可能性が高いことは明らかです(たとえば、POSIX ACLでは機能しません)。特にそれを実装しない限り)。
したがって、3つのオプションがあります。
- 必要なユーザーにフォークおよび
setgid()
/setuid()
します。通信が必要な場合は、フォークする前pipe(2)
に使用してください。socketpair(2)
seteuid()
必要に応じてフォークしたり、周りを回ったりしないでくださいsetegid()
(安全性が低い:誤ってサーバーを危険にさらす可能性が高くなります)。
- システムのクレデンシャルを台無しにしないでください。手動で権限の適用を行います(安全性が低い:権限が間違っている可能性が高くなります)。
デーモンと通信する必要がある場合、ソケットまたはパイプを介して通信するのは難しいかもしれませんが、最初のオプションは実際にはそれを実行するための適切な安全な方法です。たとえば、sshが特権分離を行う方法をご覧ください。また、アーキテクチャを変更して、通信の代わりにプロセスがメモリまたはディスクスペースを共有できるかどうかを検討することもできます。
ユーザーごとに個別のプロセスを実行することを検討したが、単一のリスニングTCPポートが必要であるとおっしゃいました。あなたはまだこれを行うことができます。マスターデーモンにTCPポートをリッスンさせ、各ユーザーデーモンに要求をディスパッチし、必要に応じて(たとえば、Unixドメインソケットを介して)通信するだけです。これは実際には、フォークマスターデーモンを使用するのとほぼ同じです。後者の方が実装しやすいと思います。
さらに読む:credentials(7)
マンページ。Linuxにはファイルシステムuid/gidsがあることにも注意してください。これは、信号の送信などの他のものを除いて、効果的なuid/gidsとほぼ同じです。ユーザーがシェルアクセス権を持たず、任意のコードを実行できない場合は、違いを心配する必要はありません。