changeset 1025:49a126e8aed0

irccd: transport can now set an uid/gid
author David Demelier <markand@malikania.fr>
date Wed, 24 Feb 2021 09:38:02 +0100
parents 11b75fdc84de
children 724ecacb5a17
files CHANGES.md irccd/conf.y irccd/irccd.conf irccd/lex.l irccd/transport.c irccd/transport.h man/irccd.conf.5
diffstat 7 files changed, 182 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES.md	Tue Feb 23 20:57:37 2021 +0100
+++ b/CHANGES.md	Wed Feb 24 09:38:02 2021 +0100
@@ -15,6 +15,8 @@
 - Irccd keeps track of nicknames in channels by capturing join/part/kick and
   mode changes. It is now more convenient from the plugins to quickly inspect if
   someone is present on a channel.
+- It is now possible to change uid/gid of the transport socket file. The file is
+  also created with permissions 664.
 
 irccdctl
 --------
--- a/irccd/conf.y	Tue Feb 23 20:57:37 2021 +0100
+++ b/irccd/conf.y	Wed Feb 24 09:38:02 2021 +0100
@@ -19,7 +19,9 @@
 %{
 
 #include <err.h>
+#include <grp.h>
 #include <limits.h>
+#include <pwd.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -59,6 +61,11 @@
 	struct string_list *events;
 };
 
+struct transport_params {
+	uid_t uid;
+	gid_t gid;
+};
+
 struct server_params {
 	char *hostname;
 	char *password;
@@ -124,6 +131,8 @@
 %union {
 	int ival;
 	char *sval;
+	uid_t uid;
+	gid_t gid;
 
 	struct pair *pair;
 	struct pair_list *pair_list;
@@ -134,6 +143,7 @@
 	struct server_params *server;
 	struct plugin_params *plugin;
 	struct rule_params *rule;
+	struct transport_params *tpt;
 };
 
 %token <ival> T_NUMBER T_LOG_VERBOSITY T_RULE_ACTION
@@ -145,6 +155,7 @@
 %token T_COMMA
 %token T_CONFIG
 %token T_EVENTS
+%token T_GID
 %token T_HOOK
 %token T_HOSTNAME
 %token T_IDENT
@@ -166,12 +177,17 @@
 %token T_TEMPLATES
 %token T_TO
 %token T_TRANSPORT
+%token T_UID
+%token T_WITH
 
 %type <ival> log_verbosity
 %type <sval> plugin_location
 %type <plugin> plugin_params plugin_params_opt
 %type <rule> rule_params rule_params_opt
 %type <server> server_params
+%type <uid> transport_params_uid
+%type <gid> transport_params_gid
+%type <tpt> transport_params
 
 %type <pair> pair
 %type <pair_list> pair_list plugin_templates plugin_config plugin_paths
@@ -195,50 +211,6 @@
 	| hook
 	;
 
-log_verbosity
-	: T_LOG_VERBOSITY
-	{
-		$$ = $1;
-	}
-	|
-	{
-		$$ = 0;
-	}
-	;
-
-logs
-	: T_LOGS log_verbosity
-	{
-		irc_log_set_verbose($2);
-	}
-	| T_LOGS log_verbosity T_TO T_LOG_TYPE
-	{
-		irc_log_set_verbose($2);
-
-		if (strcmp($4, "console") == 0)
-			irc_log_to_console();
-		else if (strcmp($4, "syslog") == 0)
-			irc_log_to_syslog();
-		else
-			errx(1, "missing log file path");
-
-		free($4);
-	}
-	| T_LOGS log_verbosity T_TO T_LOG_TYPE T_STRING
-	{
-		irc_log_to_file($4);
-		free($4);
-	}
-	;
-
-transport
-	: T_TRANSPORT T_TO T_STRING
-	{
-		transport_bind($3);
-		free($3);
-	}
-	;
-
 string
 	: T_STRING
 	{
@@ -283,6 +255,102 @@
 	}
 	;
 
+log_verbosity
+	: T_LOG_VERBOSITY
+	{
+		$$ = $1;
+	}
+	|
+	{
+		$$ = 0;
+	}
+	;
+
+logs
+	: T_LOGS log_verbosity
+	{
+		irc_log_set_verbose($2);
+	}
+	| T_LOGS log_verbosity T_TO T_LOG_TYPE
+	{
+		irc_log_set_verbose($2);
+
+		if (strcmp($4, "console") == 0)
+			irc_log_to_console();
+		else if (strcmp($4, "syslog") == 0)
+			irc_log_to_syslog();
+		else
+			errx(1, "missing log file path");
+
+		free($4);
+	}
+	| T_LOGS log_verbosity T_TO T_LOG_TYPE T_STRING
+	{
+		irc_log_to_file($4);
+		free($4);
+	}
+	;
+
+transport_params_uid
+	: T_UID T_NUMBER
+	{
+		$$ = (uid_t)$2;
+	}
+	| T_UID T_STRING
+	{
+		struct passwd *pwd;
+
+		if (!(pwd = getpwnam($2)))
+			errx(1, "invalid uid: %s", $2);
+
+		free($2);
+		$$ = pwd->pw_uid;
+	}
+	;
+
+transport_params_gid
+	: T_GID T_NUMBER
+	{
+		$$ = (gid_t)$2;
+	}
+	| T_GID T_STRING
+	{
+		struct group *grp;
+
+		if (!(grp = getgrnam($2)))
+			errx(1, "invalid uid: %s", $2);
+
+		free($2);
+		$$ = grp->gr_gid;
+	}
+	;
+
+transport_params
+	: T_WITH transport_params_uid transport_params_gid
+	{
+		$$ = irc_util_malloc(sizeof (*$$));
+		$$->uid = $2;
+		$$->gid = $3;
+	}
+	|
+	{
+		$$ = NULL;
+	}
+	;
+
+transport
+	: T_TRANSPORT T_TO T_STRING transport_params
+	{
+		if ($4)
+			transport_bindp($3, $4->uid, $4->gid);
+		else
+			transport_bind($3);
+
+		free($3);
+		free($4);
+	}
+	;
+
 rule_params
 	: T_SERVERS string_list T_SEMICOLON rule_params
 	{
--- a/irccd/irccd.conf	Tue Feb 23 20:57:37 2021 +0100
+++ b/irccd/irccd.conf	Wed Feb 24 09:38:02 2021 +0100
@@ -1,7 +1,7 @@
 #
 # This is an example of irccd.conf file.
 #
-# Comments start with a '#' like this header and until the end of lines.
+# Comments start with a '#' like this header and until ends at the end of line.
 #
 # See the irccd.conf(5) manual page for details of the file syntax and
 # available options.
@@ -19,10 +19,10 @@
 logs to console
 
 #
-# Verbose on syslog
+# Verbose on syslog:
 # logs verbose to syslog
 #
-# Explicitly quiet to a file
+# Explicitly quiet to a file:
 # logs quiet to file "/var/log/irccd/messages"
 #
 
@@ -33,10 +33,17 @@
 # Enable irccd control through a UNIX domain socket via TCP. This is required
 # for the irccdctl utility.
 #
-# Default is /tmp/irccd.sock
+# You must use a quoted string because the parser does not understand a string
+# starting with a '/' yet.
 #
 
-transport to /tmp/irccd.sock
+transport to "/tmp/irccd.sock"
+
+#
+# You can use user/group with both names instead of numeric literals.
+# transport to "/tmp/irccd.sock" with uid "www" gid "www"
+# transport to "/tmp/irccd.sock" with uid 1000 gid "users"
+#
 
 #
 # server
--- a/irccd/lex.l	Tue Feb 23 20:57:37 2021 +0100
+++ b/irccd/lex.l	Wed Feb 24 09:38:02 2021 +0100
@@ -23,6 +23,8 @@
 
 %{
 
+#include <sys/types.h>
+
 #include <irccd/limits.h>
 #include <irccd/rule.h>
 
@@ -33,6 +35,7 @@
 channels        channels
 config          config
 events          events
+gid             gid
 hook            hook
 hostname        hostname
 ident           ident
@@ -56,6 +59,8 @@
 templates       templates
 to              to
 transport       transport
+uid             uid
+with            with
 
 brace_open      \{
 brace_close     \}
@@ -79,6 +84,7 @@
 {comma}                 return T_COMMA;
 {config}                return T_CONFIG;
 {events}                return T_EVENTS;
+{gid}                   return T_GID;
 {hook}                  return T_HOOK;
 {hostname}              return T_HOSTNAME;
 {ident}                 return T_IDENT;
@@ -98,6 +104,8 @@
 {ssl}                   return T_SSL;
 {templates}             return T_TEMPLATES;
 {to}                    return T_TO;
+{uid}                   return T_UID;
+{with}                  return T_WITH;
 
 {log_verbosity}         {
                                 if (strcmp(yytext, "quiet") == 0)
--- a/irccd/transport.c	Tue Feb 23 20:57:37 2021 +0100
+++ b/irccd/transport.c	Wed Feb 24 09:38:02 2021 +0100
@@ -17,6 +17,7 @@
  */
 
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <assert.h>
 #include <errno.h>
@@ -39,10 +40,12 @@
 static int fd = -1;
 
 int
-transport_bind(const char *path)
+wrap_bind(const char *path, uid_t *uid, gid_t *gid)
 {
 	assert(path);
 
+	int oldumask;
+
 	addr.sun_family = PF_LOCAL;
 
 	if (strlcpy(addr.sun_path, path, sizeof (addr.sun_path)) >= sizeof (addr.sun_path)) {
@@ -51,18 +54,30 @@
 	}
 
 	/* Silently remove the file first. */
-	unlink(addr.sun_path);
+	unlink(path);
 
 	if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0)
 		goto err;
+
+	/* -ux, -gx, -owx */
+	oldumask = umask(S_IXUSR | S_IXGRP | S_IWOTH | S_IXOTH);
+
 	if (bind(fd, (const struct sockaddr *)&addr, sizeof (addr)) < 0)
 		goto err;
+	if (uid && gid && chown(path, *uid, *gid) < 0)
+		goto err;
+
+	umask(oldumask);
+
 	if (listen(fd, 16) < 0)
 		goto err;
 
 	irc_log_info("transport: listening on %s", path);
 	irc_log_debug("transport: file descriptor %d", fd);
 
+	if (uid && gid)
+		irc_log_info("transport: uid=%d, gid=%d", (int)*uid, (int)*gid);
+
 	return 0;
 
 err:
@@ -76,6 +91,18 @@
 	return -1;
 }
 
+int
+transport_bind(const char *path)
+{
+	return wrap_bind(path, NULL, NULL);
+}
+
+int
+transport_bindp(const char *path, uid_t uid, gid_t gid)
+{
+	return wrap_bind(path, &uid, &gid);
+}
+
 void
 transport_prepare(struct pollfd *pfd)
 {
--- a/irccd/transport.h	Tue Feb 23 20:57:37 2021 +0100
+++ b/irccd/transport.h	Wed Feb 24 09:38:02 2021 +0100
@@ -19,6 +19,8 @@
 #ifndef IRCCD_TRANSPORT_H
 #define IRCCD_TRANSPORT_H
 
+#include <sys/types.h>
+
 #include "limits.h"
 
 struct pollfd;
@@ -28,6 +30,9 @@
 int
 transport_bind(const char *);
 
+int
+transport_bindp(const char *, uid_t, gid_t);
+
 void
 transport_prepare(struct pollfd *);
 
--- a/man/irccd.conf.5	Tue Feb 23 20:57:37 2021 +0100
+++ b/man/irccd.conf.5	Wed Feb 24 09:38:02 2021 +0100
@@ -113,10 +113,18 @@
 utility or any networking program that can communicate through a UNIX domain
 socket.
 .Pp
-.Ar transport to path
+.Ar transport to path [with uid value gid value]
+.Pp
+Create the UNIX domain socket on
+.Pa path .
 .Pp
-Enable transport on
-.Pa path .
+The optional
+.Ar uid
+and
+.Ar gid
+keywords can take an optional
+.Ar value
+to change socket owner and group respectively, it can be a string or a number.
 .\" server
 .Ss server
 This section is used to connect to one or more server. Create a new server
@@ -277,6 +285,9 @@
 # Logs to syslog instead of console (which is the default).
 logs verbose to syslog
 
+# Enable transport with default permissions.
+transport to "/tmp/irccd.sock"
+
 #
 # Create a server "example" that connect to example.org using "fr" as nickname,
 # "francis" as username and "Francis Meyer" as realname.