Переглянути джерело

klishd: The daemon's listen socket can be chown-ed and chmod-ed.

The klishd config file can contain the following new options:

* UnixSocketUser
* UnixSocketGroup
* UnixSocketMode

The klishd daemon will chmod or/and chown created listen socket to the
specified values. If options are not specified the klishd will not perform
any chmod or chown.

Thanks to A. Eremin <korbezolympus@gmail.com> and
V. Chashchin <v.chashchin@nagtech.ru> for the original patch.
Serj Kalichev 1 день тому
батько
коміт
811a4a8549
4 змінених файлів з 106 додано та 21 видалено
  1. 55 15
      bin/klishd/klishd.c
  2. 29 5
      bin/klishd/opts.c
  3. 12 1
      bin/klishd/private.h
  4. 10 0
      klishd.conf

+ 55 - 15
bin/klishd/klishd.c

@@ -49,7 +49,7 @@
 // Local static functions
 bool_t daemonize(const char *pidfile);
 bool_t kentry_entrys_is_empty(const kentry_t *entry);
-static int create_listen_unix_sock(const char *path);
+static int create_listen_unix_sock(struct unix_socket_config *socket_cfg);
 static kscheme_t *load_all_dbs(const char *dbs,
 	faux_ini_t *global_config, faux_error_t *error);
 static bool_t clear_scheme(kscheme_t *scheme, faux_error_t *error);
@@ -127,8 +127,8 @@ int main(int argc, char **argv)
 	}
 
 	// Listen socket
-	syslog(LOG_DEBUG, "Create listen UNIX socket: %s", opts->unix_socket_path);
-	listen_unix_sock = create_listen_unix_sock(opts->unix_socket_path);
+	syslog(LOG_DEBUG, "Create listen UNIX socket: %s", opts->socket_cfg.path);
+	listen_unix_sock = create_listen_unix_sock(&opts->socket_cfg);
 	if (listen_unix_sock < 0)
 		goto err;
 	syslog(LOG_DEBUG, "Listen socket %d", listen_unix_sock);
@@ -444,22 +444,23 @@ static bool_t clear_scheme(kscheme_t *scheme, faux_error_t *error)
  * Previously removes old socket's file from filesystem. Note daemon must check
  * for already working daemon to don't duplicate.
  *
- * @param [in] path Socket path within filesystem.
+ * @param [in] socket_cfg Socket config.
  * @return Socket descriptor of < 0 on error.
  */
-static int create_listen_unix_sock(const char *path)
+
+static int create_listen_unix_sock(struct unix_socket_config *socket_cfg)
 {
 	int sock = -1;
 	int opt = 1;
 	struct sockaddr_un laddr = {};
 
-	assert(path);
-	if (!path)
+	assert(socket_cfg->path);
+	if (!socket_cfg->path)
 		return -1;
 
 	if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
 		syslog(LOG_ERR, "Can't create socket: %s", strerror(errno));
-		goto err;
+		return -1;
 	}
 	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
 		syslog(LOG_ERR, "Can't set socket options: %s", strerror(errno));
@@ -467,27 +468,66 @@ static int create_listen_unix_sock(const char *path)
 	}
 
 	// Remove old (lost) socket's file
-	unlink(path);
+	unlink(socket_cfg->path);
 
 	laddr.sun_family = AF_UNIX;
-	strncpy(laddr.sun_path, path, USOCK_PATH_MAX);
+	strncpy(laddr.sun_path, socket_cfg->path, USOCK_PATH_MAX);
 	laddr.sun_path[USOCK_PATH_MAX - 1] = '\0';
 	if (bind(sock, (struct sockaddr *)&laddr, sizeof(laddr))) {
-		syslog(LOG_ERR, "Can't bind socket %s: %s", path, strerror(errno));
+		syslog(LOG_ERR, "Can't bind socket %s: %s", socket_cfg->path, strerror(errno));
 		goto err;
 	}
 
+	if (socket_cfg->user || socket_cfg->group) {
+		uid_t uid = -1;
+		gid_t gid = -1;
+
+		if (socket_cfg->user) {
+			if (!faux_sysdb_uid_by_name(socket_cfg->user, &uid)) {
+				syslog(LOG_ERR, "Can't get UID for socket %s: %s",
+					socket_cfg->path, strerror(errno));
+				goto err;
+			}
+		}
+
+		if (socket_cfg->group) {
+			if (!faux_sysdb_gid_by_name(socket_cfg->group, &gid)) {
+				syslog(LOG_ERR, "Can't get GID for socket %s: %s",
+					socket_cfg->path, strerror(errno));
+				goto err;
+			}
+		}
+
+		if (chown(socket_cfg->path, uid, gid)) {
+			syslog(LOG_ERR, "Can't chown socket %s: %s",
+				socket_cfg->path, strerror(errno));
+			goto err;
+		}
+	}
+
+	if (socket_cfg->mode) {
+		unsigned int mode = 0;
+
+		if (!faux_conv_atoui(socket_cfg->mode, &mode, 8)) {
+			syslog(LOG_ERR, "Can't parse socket %s mode", socket_cfg->path);
+			goto err;
+		}
+		if (chmod(socket_cfg->path, mode)) {
+			syslog(LOG_ERR, "Can't chmod socket %s: %s", socket_cfg->path, strerror(errno));
+			goto err;
+		}
+	}
+
 	if (listen(sock, 128)) {
-		unlink(path);
-		syslog(LOG_ERR, "Can't listen on socket %s: %s", path, strerror(errno));
+		syslog(LOG_ERR, "Can't listen on socket %s: %s", socket_cfg->path, strerror(errno));
 		goto err;
 	}
 
 	return sock;
 
 err:
-	if (sock >= 0)
-		close(sock);
+	close(sock);
+	unlink(socket_cfg->path);
 
 	return -1;
 }

+ 29 - 5
bin/klishd/opts.c

@@ -36,7 +36,7 @@ struct options *opts_init(void)
 	// Initialize
 	opts->pidfile = faux_str_dup(DEFAULT_PIDFILE);
 	opts->cfgfile = faux_str_dup(DEFAULT_CFGFILE);
-	opts->unix_socket_path = faux_str_dup(KLISH_DEFAULT_UNIX_SOCKET_PATH);
+	opts->socket_cfg.path = faux_str_dup(KLISH_DEFAULT_UNIX_SOCKET_PATH);
 	opts->cfgfile_userdefined = BOOL_FALSE;
 	opts->foreground = BOOL_FALSE; // Daemonize by default
 	opts->verbose = BOOL_FALSE;
@@ -53,7 +53,10 @@ void opts_free(struct options *opts)
 {
 	faux_str_free(opts->pidfile);
 	faux_str_free(opts->cfgfile);
-	faux_str_free(opts->unix_socket_path);
+	faux_str_free(opts->socket_cfg.path);
+	faux_str_free(opts->socket_cfg.user);
+	faux_str_free(opts->socket_cfg.group);
+	faux_str_free(opts->socket_cfg.mode);
 	faux_str_free(opts->dbs);
 	faux_free(opts);
 }
@@ -177,8 +180,26 @@ faux_ini_t *config_parse(const char *cfgfile, struct options *opts)
 
 	// UnixSocketPath
 	if ((tmp = faux_ini_find(ini, "UnixSocketPath"))) {
-		faux_str_free(opts->unix_socket_path);
-		opts->unix_socket_path = faux_str_dup(tmp);
+		faux_str_free(opts->socket_cfg.path);
+		opts->socket_cfg.path = faux_str_dup(tmp);
+	}
+
+	// UnixSocketUser
+	if ((tmp = faux_ini_find(ini, "UnixSocketUser"))) {
+		faux_str_free(opts->socket_cfg.user);
+		opts->socket_cfg.user = faux_str_dup(tmp);
+	}
+
+	// UnixSocketGroup
+	if ((tmp = faux_ini_find(ini, "UnixSocketGroup"))) {
+		faux_str_free(opts->socket_cfg.group);
+		opts->socket_cfg.group = faux_str_dup(tmp);
+	}
+
+	// UnixSocketMode
+	if ((tmp = faux_ini_find(ini, "UnixSocketMode"))) {
+		faux_str_free(opts->socket_cfg.mode);
+		opts->socket_cfg.mode = faux_str_dup(tmp);
 	}
 
 	// DBs
@@ -204,7 +225,10 @@ int opts_show(struct options *opts)
 	syslog(LOG_DEBUG, "opts: LogFacility = %s\n", faux_log_facility_str(opts->log_facility));
 	syslog(LOG_DEBUG, "opts: PIDPath = %s\n", opts->pidfile);
 	syslog(LOG_DEBUG, "opts: ConfigPath = %s\n", opts->cfgfile);
-	syslog(LOG_DEBUG, "opts: UnixSocketPath = %s\n", opts->unix_socket_path);
+	syslog(LOG_DEBUG, "opts: UnixSocketPath = %s\n", opts->socket_cfg.path);
+	syslog(LOG_DEBUG, "opts: UnixSocketUser = %s\n", opts->socket_cfg.user ? opts->socket_cfg.user : "None");
+	syslog(LOG_DEBUG, "opts: UnixSocketGroup = %s\n", opts->socket_cfg.group ? opts->socket_cfg.group : "None");
+	syslog(LOG_DEBUG, "opts: UnixSocketMode = %s\n", opts->socket_cfg.mode ? opts->socket_cfg.mode : "None");
 	syslog(LOG_DEBUG, "opts: DBs = %s\n", opts->dbs);
 
 	return 0;

+ 12 - 1
bin/klishd/private.h

@@ -11,13 +11,24 @@
 #define DEFAULT_DBS "libxml2"
 
 
+/** @brief Unix socket parameters specified in the config file.
+ *
+ * It is used to configure the permissions and ownership of the socket file.
+ */
+struct unix_socket_config {
+	char *path;
+	char *user;
+	char *group;
+	char *mode;
+ };
+
 /** @brief Command line and config file options
  */
 struct options {
 	char *pidfile;
 	char *cfgfile;
 	bool_t cfgfile_userdefined;
-	char *unix_socket_path;
+	struct unix_socket_config socket_cfg;
 	char *dbs;
 	bool_t foreground; // Don't daemonize
 	bool_t verbose;

+ 10 - 0
klishd.conf

@@ -5,5 +5,15 @@
 # uses /tmp/klish-unix-socket path.
 #UnixSocketPath=/tmp/klish-unix-socket
 
+# The created listening UNIX domain socket can be "chown"-ed to the specified
+# user and group. By default klishd will not perform "chown".
+#UnixSocketUser=klish
+#UnixSocketGroup=klish
+
+# The created listening UNIX domain socket can be "chmod"-ed to the specified
+# value. By default klishd will not perform "chmod".
+#UnixSocketMode=0755
+
+
 DBs=libxml2
 DB.libxml2.XMLPath=/home/pkun/work/klish/examples/simple