Skip to content

Commit 9182c42

Browse files
committed
Allow setting the user which we drop permissions to using suid.
1 parent 83168cd commit 9182c42

File tree

3 files changed

+30
-7
lines changed

3 files changed

+30
-7
lines changed

aiosmtpd/docs/NEWS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
Added
1010
-----
1111
* Unthreaded Controllers (Closes #160)
12+
* Ability to drop permissions to a user other than ``nobody`` using ``-S``
1213

1314
Fixed/Improved
1415
--------------

aiosmtpd/main.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,18 @@ def _parser() -> ArgumentParser:
4848
default=True,
4949
action="store_false",
5050
help=(
51-
"This program generally tries to setuid ``nobody``, unless this "
52-
"flag is set. The setuid call will fail if this program is not "
53-
"run as root (in which case, use this flag)."
51+
"This program uses setuid to drop permissions unless this flag "
52+
"is set. The setuid call will fail if this program is not run "
53+
"as root (in which case, use this flag)."
54+
),
55+
)
56+
parser.add_argument(
57+
"-S",
58+
"--suid-user",
59+
dest="suid_user",
60+
default="nobody",
61+
help=(
62+
"The user to change to using suid; defaults to ``nobody``."
5463
),
5564
)
5665
parser.add_argument(
@@ -224,12 +233,13 @@ def main(args: Optional[Sequence[str]] = None) -> None:
224233
file=sys.stderr,
225234
)
226235
sys.exit(1)
227-
nobody = pwd.getpwnam("nobody").pw_uid
236+
suid_user_id = pwd.getpwnam(args.suid_user).pw_uid
228237
try:
229-
os.setuid(nobody)
238+
os.setuid(suid_user_id)
230239
except PermissionError:
231240
print(
232-
'Cannot setuid "nobody"; try running with -n option.', file=sys.stderr
241+
f'Cannot setuid to "{args.suid_user}"; try running with -n option.',
242+
file=sys.stderr,
233243
)
234244
sys.exit(1)
235245

aiosmtpd/tests/test_main.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# SPDX-License-Identifier: Apache-2.0
33

44
import asyncio
5+
from collections import namedtuple
56
import logging
67
import multiprocessing as MP
78
import os
@@ -141,6 +142,17 @@ def test_setuid(self, nobody_uid, mocker):
141142
main(args=())
142143
mock.assert_called_with(nobody_uid)
143144

145+
def test_setuid_other(self, nobody_uid, mocker):
146+
other_user = namedtuple(
147+
"pwnam",
148+
["pw_uid", "pw_dir", "pw_shell"],
149+
)(42, "/", "/bin/sh")
150+
mock_getpwnam = mocker.patch("pwd.getpwnam", return_value=other_user)
151+
mock_suid = mocker.patch("os.setuid")
152+
main(args=("-S", "other"))
153+
mock_getpwnam.assert_called_with("other")
154+
mock_suid.assert_called_with(42)
155+
144156
def test_setuid_permission_error(self, nobody_uid, mocker, capsys):
145157
mock = mocker.patch("os.setuid", side_effect=PermissionError)
146158
with pytest.raises(SystemExit) as excinfo:
@@ -149,7 +161,7 @@ def test_setuid_permission_error(self, nobody_uid, mocker, capsys):
149161
mock.assert_called_with(nobody_uid)
150162
assert (
151163
capsys.readouterr().err
152-
== 'Cannot setuid "nobody"; try running with -n option.\n'
164+
== 'Cannot setuid to "nobody"; try running with -n option.\n'
153165
)
154166

155167
def test_setuid_no_pwd_module(self, nobody_uid, mocker, capsys):

0 commit comments

Comments
 (0)