[Dnsmasq-discuss] [PATCH] add nouser/nogroup options
Leon M. Busch-George
leon at georgemail.de
Thu Aug 6 09:45:27 UTC 2026
From: "Leon M. Busch-George" <leon at georgemail.eu>
Without this patch, dnsmasq wont start in namespaces without group ID
mappings unless setgroups is explicitly allowed (e.g. write "allow" to
/proc/self/setgroups).
This happens even if the target gid matches the current one.
Add options to disable changing user and group ID.
---
man/dnsmasq.8 | 10 ++++++++++
man/fr/dnsmasq.8 | 10 ++++++++++
src/dnsmasq.c | 4 ++--
src/dnsmasq.h | 4 +++-
src/option.c | 6 ++++++
5 files changed, 31 insertions(+), 3 deletions(-)
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index 780d6d5..9bbc334 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -178,6 +178,16 @@ Specify the group which dnsmasq will run
as. The default is "dip", if available, to facilitate access to
/etc/ppp/resolv.conf which is not normally world readable.
.TP
+.B --nouser
+Do not drop privileges by changing user id after startup, even if
+.B --user
+is specified.
+.TP
+.B --nogroup
+Do not drop privileges by changing group id after startup, even if
+.B --group
+is specified.
+.TP
.B \-v, --version
Print the version number.
.TP
diff --git a/man/fr/dnsmasq.8 b/man/fr/dnsmasq.8
index dc2fdc0..3cf80f8 100644
--- a/man/fr/dnsmasq.8
+++ b/man/fr/dnsmasq.8
@@ -172,6 +172,16 @@ Spécifie le groupe sous lequel Dnsmasq s'exécute. Par défaut, il s'agit du
groupe "dip", afin de faciliter l'accès au fichier /etc/ppp/resolv.conf qui
n'est en général pas en lecture par tout le monde.
.TP
+.B --nouser
+Ne pas abandonner les privilèges en changeant d'utilisateur après le démarrage, même si
+.B --user
+est spécifié.
+.TP
+.B --nogroup
+Ne pas abandonner les privilèges en changeant de groupe après le démarrage, même si
+.B --group
+est spécifié.
+.TP
.B \-v, --version
Imprime le numéro de version.
.TP
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 8fcbbda..58f035c 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -742,7 +742,7 @@ int main (int argc, char **argv)
gid_t dummy;
/* remove all supplementary groups */
- if (gp &&
+ if (gp && !option_bool(OPT_NOGROUP) &&
(setgroups(0, &dummy) == -1 ||
setgid(gp->gr_gid) == -1))
{
@@ -750,7 +750,7 @@ int main (int argc, char **argv)
_exit(0);
}
- if (ent_pw && ent_pw->pw_uid != 0)
+ if (ent_pw && ent_pw->pw_uid != 0 && !option_bool(OPT_NOUSER))
{
#if defined(HAVE_LINUX_NETWORK)
/* Need to be able to drop root. */
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index c5b0887..3d50da9 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -296,7 +296,9 @@ struct event_desc {
#define OPT_LEASEQUERY 77
#define OPT_LOG_ONLY_FAILED 78
#define OPT_LOG_MALLOC 79
-#define OPT_LAST 80
+#define OPT_NOUSER 80
+#define OPT_NOGROUP 81
+#define OPT_LAST 82
#define OPTION_BITS (sizeof(unsigned int)*8)
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
diff --git a/src/option.c b/src/option.c
index 051555a..550b7a9 100644
--- a/src/option.c
+++ b/src/option.c
@@ -201,6 +201,8 @@ struct myoption {
#define LOPT_LEASEQUERY 389
#define LOPT_SPLIT_RELAY 390
#define LOPT_LOG_MALLOC 391
+#define LOPT_NOUSER 392
+#define LOPT_NOGROUP 393
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -216,6 +218,8 @@ static const struct myoption opts[] =
{ "log-queries", 2, 0, 'q' },
{ "user", 2, 0, 'u' },
{ "group", 2, 0, 'g' },
+ { "nouser", 0, 0, LOPT_NOUSER },
+ { "nogroup", 0, 0, LOPT_NOGROUP },
{ "resolv-file", 2, 0, 'r' },
{ "servers-file", 1, 0, LOPT_SERVERS_FILE },
{ "mx-host", 1, 0, 'm' },
@@ -435,6 +439,7 @@ static struct {
{ LOPT_FILTER_RR, ARG_DUP, "<RR-type>", gettext_noop("Don't include resource records of the given type in DNS answers."), NULL },
{ 'F', ARG_DUP, "<ipaddr>,...", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
{ 'g', ARG_ONE, "<groupname>", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
+ { LOPT_NOGROUP, OPT_NOGROUP, NULL, gettext_noop("Do NOT drop privileges by changing group."), NULL },
{ 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
{ LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL },
{ LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL },
@@ -486,6 +491,7 @@ static struct {
{ LOPT_MINCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live floor for cache."), NULL },
{ LOPT_FAST_RETRY, ARG_ONE, "<milliseconds>", gettext_noop("Retry DNS queries after this many milliseconds."), NULL},
{ 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
+ { LOPT_NOUSER, OPT_NOUSER, NULL, gettext_noop("Do NOT drop privileges by changing user."), NULL },
{ 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
{ 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
{ 'V', ARG_DUP, "<ipaddr>,<ipaddr>,<netmask>", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
--
2.55.0
More information about the Dnsmasq-discuss
mailing list