[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