Blame SOURCES/bz1477563-fix-keepalived_script-user.patch

00db14
From 99f31a89d2f5803fe2d6229f2557e72efb3ef95f Mon Sep 17 00:00:00 2001
00db14
From: Quentin Armitage <quentin@armitage.org.uk>
00db14
Date: Tue, 28 Mar 2017 09:11:44 +0100
00db14
Subject: [PATCH] Make dynamic flag bool
00db14
00db14
Signed-off-by: Quentin Armitage <quentin@armitage.org.uk>
00db14
00db14
Fix releasing malloc'd memory for saved core pattern
00db14
00db14
Signed-off-by: Quentin Armitage <quentin@armitage.org.uk>
00db14
00db14
Fix detecting default script uid/gid
00db14
00db14
Signed-off-by: Quentin Armitage <quentin@armitage.org.uk>
00db14
00db14
Don't complain about keepalived_script user if not needed
00db14
00db14
keepalived logged a warning every time if the keepalived_script user
00db14
didn't exist. We only need that warning if there is a script that uses
00db14
the default user, and an alternative defult user isn't specified.
00db14
00db14
Signed-off-by: Quentin Armitage <quentin@armitage.org.uk>
00db14
---
00db14
 doc/keepalived.conf.SYNOPSIS    |  30 +++++----
00db14
 doc/man/man5/keepalived.conf.5  |   4 +-
00db14
 keepalived/check/check_misc.c   |  72 ++++++++++++++++-----
00db14
 keepalived/check/check_parser.c |   9 +--
00db14
 keepalived/core/global_parser.c |  49 +-------------
00db14
 keepalived/core/main.c          |  15 +----
00db14
 keepalived/include/check_misc.h |   2 +-
00db14
 keepalived/include/main.h       |   2 -
00db14
 keepalived/vrrp/vrrp_data.c     |   3 +-
00db14
 keepalived/vrrp/vrrp_parser.c   |  46 ++++++++++---
00db14
 keepalived/vrrp/vrrp_print.c    |   1 +
00db14
 lib/notify.c                    | 140 ++++++++++++++++++++++++++++++++++------
00db14
 lib/notify.h                    |   7 +-
00db14
 13 files changed, 242 insertions(+), 138 deletions(-)
00db14
00db14
diff --git a/doc/keepalived.conf.SYNOPSIS b/doc/keepalived.conf.SYNOPSIS
00db14
index 5b1dfb8..90eb83d 100644
00db14
--- a/doc/keepalived.conf.SYNOPSIS
00db14
+++ b/doc/keepalived.conf.SYNOPSIS
00db14
@@ -568,12 +568,14 @@ virtual_server group <STRING>      {	# VS group declaration
00db14
         weight <INTEGER>		# weight to use (default: 1)
00db14
         inhibit_on_failure		# Set weight to 0 on healthchecker
00db14
 					#  failure
00db14
-        notify_up <STRING>|<QUOTED-STRING> # Script to launch when
00db14
-					   #  healthchecker consider service
00db14
-					   #  as up.
00db14
-        notify_down <STRING>|<QUOTED-STRING> # Script to launch when
00db14
-					     #  healthchecker consider service
00db14
-					     #  as down.
00db14
+        notify_up <STRING>|<QUOTED-STRING> [username [groupname]]
00db14
+					# Script to launch when
00db14
+					#  healthchecker consider service
00db14
+					#  as up.
00db14
+        notify_down <STRING>|<QUOTED-STRING> [username [groupname]]
00db14
+					# Script to launch when
00db14
+					#  healthchecker consider service
00db14
+					#  as down.
00db14
 
00db14
         HTTP_GET|SSL_GET {		# HTTP and SSL healthcheckers
00db14
             url {			# A set of url to test
00db14
@@ -603,8 +605,8 @@ virtual_server group <STRING>      {	# VS group declaration
00db14
     real_server <IP ADDRESS> <PORT> {	# Idem
00db14
         weight <INTEGER>		# Idem
00db14
         inhibit_on_failure		# Idem
00db14
-        notify_up <STRING>|<QUOTED-STRING> # Idem
00db14
-        notify_down <STRING>|<QUOTED-STRING> # Idem
00db14
+        notify_up <STRING>|<QUOTED-STRING> [username [groupname]] # Idem
00db14
+        notify_down <STRING>|<QUOTED-STRING> [username [groupname]] # Idem
00db14
 
00db14
         TCP_CHECK {			# TCP healthchecker
00db14
             connect_ip <IP ADDRESS> # IP address to connect
00db14
@@ -620,8 +622,8 @@ virtual_server group <STRING>      {	# VS group declaration
00db14
     real_server <IP ADDRESS> <PORT> {	# Idem
00db14
         weight <INTEGER>		# Idem
00db14
         inhibit_on_failure		# Idem
00db14
-        notify_up <STRING>|<QUOTED-STRING> # Idem
00db14
-        notify_down <STRING>|<QUOTED-STRING> # Idem
00db14
+        notify_up <STRING>|<QUOTED-STRING> [username [groupname]] # Idem
00db14
+        notify_down <STRING>|<QUOTED-STRING> [username [groupname]] # Idem
00db14
 
00db14
         SMTP_CHECK {                   # SMTP healthchecker
00db14
             connect_ip <IP ADDRESS>     # Optional IP address to connect to
00db14
@@ -658,8 +660,8 @@ virtual_server group <STRING>      {	# VS group declaration
00db14
     real_server <IP ADDRESS> <PORT> {	# Idem
00db14
         weight <INTEGER>		# Idem
00db14
         inhibit_on_failure		# Idem
00db14
-        notify_up <STRING>|<QUOTED-STRING> # Idem
00db14
-        notify_down <STRING>|<QUOTED-STRING> # Idem
00db14
+        notify_up <STRING>|<QUOTED-STRING> [username [groupname]] # Idem
00db14
+        notify_down <STRING>|<QUOTED-STRING> [username [groupname]] # Idem
00db14
 
00db14
         DNS_CHECK {                     # DNS healthchecker
00db14
             connect_ip <IP ADDRESS>     # Optional IP address to connect to
00db14
@@ -677,8 +679,8 @@ virtual_server group <STRING>      {	# VS group declaration
00db14
     real_server <IP ADDRESS> <PORT> {	# Idem
00db14
         weight <INTEGER>		# Idem
00db14
         inhibit_on_failure		# Idem
00db14
-        notify_up <STRING>|<QUOTED-STRING> # Idem
00db14
-        notify_down <STRING>|<QUOTED-STRING> # Idem
00db14
+        notify_up <STRING>|<QUOTED-STRING> [username [groupname]] # Idem
00db14
+        notify_down <STRING>|<QUOTED-STRING> [username [groupname]] # Idem
00db14
 
00db14
         MISC_CHECK {				# MISC healthchecker
00db14
             misc_path <STRING>|<QUOTED-STRING>	# External system script or program
00db14
diff --git a/doc/man/man5/keepalived.conf.5 b/doc/man/man5/keepalived.conf.5
00db14
index 9ce2206..be33063 100644
00db14
--- a/doc/man/man5/keepalived.conf.5
00db14
+++ b/doc/man/man5/keepalived.conf.5
00db14
@@ -711,10 +711,10 @@ A virtual_server can be a declaration of one of
00db14
 
00db14
            # Script to execute when healthchecker
00db14
            # considers service as up.
00db14
-           notify_up <STRING>|<QUOTED-STRING>
00db14
+           notify_up <STRING>|<QUOTED-STRING> [username [groupname]]
00db14
            # Script to execute when healthchecker
00db14
            # considers service as down.
00db14
-           notify_down <STRING>|<QUOTED-STRING>
00db14
+           notify_down <STRING>|<QUOTED-STRING> [username [groupname]]
00db14
 
00db14
            uthreshold <INTEGER> # maximum number of connections to server
00db14
            lthreshold <INTEGER> # minimum number of connections to server
00db14
diff --git a/keepalived/check/check_misc.c b/keepalived/check/check_misc.c
00db14
index ccb9b63..a041d81 100644
00db14
--- a/keepalived/check/check_misc.c
00db14
+++ b/keepalived/check/check_misc.c
00db14
@@ -44,6 +44,11 @@ static int misc_check_thread(thread_t *);
00db14
 static int misc_check_child_thread(thread_t *);
00db14
 static int misc_check_child_timeout_thread(thread_t *);
00db14
 
00db14
+static bool script_user_set;
00db14
+static bool remove_script;
00db14
+static misc_checker_t *misck_checker;
00db14
+
00db14
+
00db14
 /* Configuration stream handling */
00db14
 static void
00db14
 free_misc_check(void *data)
00db14
@@ -70,49 +75,83 @@ dump_misc_check(void *data)
00db14
 static void
00db14
 misc_check_handler(__attribute__((unused)) vector_t *strvec)
00db14
 {
00db14
-	misc_checker_t *misck_checker = (misc_checker_t *) MALLOC(sizeof (misc_checker_t));
00db14
-
00db14
-	misck_checker->uid = default_script_uid;
00db14
-	misck_checker->gid = default_script_gid;
00db14
+	misck_checker = (misc_checker_t *) MALLOC(sizeof (misc_checker_t));
00db14
 
00db14
-	/* queue new checker */
00db14
-	queue_checker(free_misc_check, dump_misc_check, misc_check_thread,
00db14
-		      misck_checker, NULL);
00db14
+	script_user_set = false;
00db14
 }
00db14
 
00db14
 static void
00db14
 misc_path_handler(vector_t *strvec)
00db14
 {
00db14
-	misc_checker_t *misck_checker = CHECKER_GET();
00db14
+	if (!misck_checker)
00db14
+		return;
00db14
+
00db14
 	misck_checker->path = CHECKER_VALUE_STRING(strvec);
00db14
 }
00db14
 
00db14
 static void
00db14
 misc_timeout_handler(vector_t *strvec)
00db14
 {
00db14
-	misc_checker_t *misck_checker = CHECKER_GET();
00db14
+	if (!misck_checker)
00db14
+		return;
00db14
+
00db14
 	misck_checker->timeout = CHECKER_VALUE_UINT(strvec) * TIMER_HZ;
00db14
 }
00db14
 
00db14
 static void
00db14
 misc_dynamic_handler(__attribute__((unused)) vector_t *strvec)
00db14
 {
00db14
-	misc_checker_t *misck_checker = CHECKER_GET();
00db14
-	misck_checker->dynamic = 1;
00db14
+	if (!misck_checker)
00db14
+		return;
00db14
+
00db14
+	misck_checker->dynamic = true;
00db14
 }
00db14
 
00db14
 static void
00db14
 misc_user_handler(vector_t *strvec)
00db14
 {
00db14
-	misc_checker_t *misck_checker = CHECKER_GET();
00db14
+	if (!misck_checker)
00db14
+		return;
00db14
 
00db14
 	if (vector_size(strvec) < 2) {
00db14
 		log_message(LOG_INFO, "No user specified for misc checker script %s", misck_checker->path);
00db14
 		return;
00db14
 	}
00db14
 
00db14
-	if (set_script_uid_gid(strvec, 1, &misck_checker->uid, &misck_checker->gid))
00db14
-		log_message(LOG_INFO, "Failed to set uid/gid for misc checker script %s", misck_checker->path);
00db14
+	if (set_script_uid_gid(strvec, 1, &misck_checker->uid, &misck_checker->gid)) {
00db14
+		log_message(LOG_INFO, "Failed to set uid/gid for misc checker script %s - removing", misck_checker->path);
00db14
+		FREE(misck_checker);
00db14
+		misck_checker = NULL;
00db14
+	}
00db14
+	else
00db14
+		script_user_set = true;
00db14
+}
00db14
+
00db14
+static void
00db14
+misc_end_handler(void)
00db14
+{
00db14
+	if (!misck_checker)
00db14
+		return;
00db14
+
00db14
+	if (!script_user_set)
00db14
+	{
00db14
+log_message(LOG_INFO, "remove_script 1 %d", remove_script);
00db14
+		if ( set_default_script_user(NULL, NULL, global_data->script_security)) {
00db14
+			log_message(LOG_INFO, "Unable to set default user for misc script %s - removing", misck_checker->path);
00db14
+			FREE(misck_checker);
00db14
+			misck_checker = NULL;
00db14
+			return;
00db14
+		}
00db14
+
00db14
+log_message(LOG_INFO, "Setting uid.gid");
00db14
+		misck_checker->uid = default_script_uid;
00db14
+		misck_checker->gid = default_script_gid;
00db14
+	}
00db14
+
00db14
+	/* queue new checker */
00db14
+	queue_checker(free_misc_check, dump_misc_check, misc_check_thread, misck_checker, NULL);
00db14
+	misck_checker = NULL;
00db14
+log_message(LOG_INFO, "Leaving misc_end_handler");
00db14
 }
00db14
 
00db14
 void
00db14
@@ -125,6 +164,7 @@ install_misc_check_keyword(void)
00db14
 	install_keyword("misc_dynamic", &misc_dynamic_handler);
00db14
 	install_keyword("warmup", &warmup_handler);
00db14
 	install_keyword("user", &misc_user_handler);
00db14
+	install_sublevel_end_handler(&misc_end_handler);
00db14
 	install_sublevel_end();
00db14
 }
00db14
 
00db14
@@ -251,13 +291,13 @@ misc_check_child_thread(thread_t * thread)
00db14
 		int status;
00db14
 		status = WEXITSTATUS(wait_status);
00db14
 		if (status == 0 ||
00db14
-		    (misck_checker->dynamic == 1 && status >= 2 && status <= 255)) {
00db14
+		    (misck_checker->dynamic && status >= 2 && status <= 255)) {
00db14
 			/*
00db14
 			 * The actual weight set when using misc_dynamic is two less than
00db14
 			 * the exit status returned.  Effective range is 0..253.
00db14
 			 * Catch legacy case of status being 0 but misc_dynamic being set.
00db14
 			 */
00db14
-			if (misck_checker->dynamic == 1 && status != 0)
00db14
+			if (misck_checker->dynamic && status != 0)
00db14
 				update_svr_wgt(status - 2, checker->vs,
00db14
 					       checker->rs, true);
00db14
 
00db14
diff --git a/keepalived/check/check_parser.c b/keepalived/check/check_parser.c
00db14
index 2adac98..382861c 100644
00db14
--- a/keepalived/check/check_parser.c
00db14
+++ b/keepalived/check/check_parser.c
00db14
@@ -322,14 +322,7 @@ inhibit_handler(__attribute__((unused)) vector_t *strvec)
00db14
 static inline notify_script_t*
00db14
 set_check_notify_script(vector_t *strvec)
00db14
 {
00db14
-	notify_script_t *script = notify_script_init(strvec, default_script_uid, default_script_gid);
00db14
-
00db14
-	if (vector_size(strvec) > 2 ) {
00db14
-		if (set_script_uid_gid(strvec, 2, &script->uid, &script->gid))
00db14
-			log_message(LOG_INFO, "Invalid user/group for quorum/notify script %s", script->name);
00db14
-	}
00db14
-
00db14
-	return script;
00db14
+	return notify_script_init(strvec, "quorum/notify", global_data->script_security);
00db14
 }
00db14
 static void
00db14
 notify_up_handler(vector_t *strvec)
00db14
diff --git a/keepalived/core/global_parser.c b/keepalived/core/global_parser.c
00db14
index 45d4cfb..a59fbc0 100644
00db14
--- a/keepalived/core/global_parser.c
00db14
+++ b/keepalived/core/global_parser.c
00db14
@@ -701,53 +701,6 @@ use_pid_dir_handler(__attribute__((unused)) vector_t *strvec)
00db14
 	use_pid_dir = true;
00db14
 }
00db14
 
00db14
-bool
00db14
-set_script_uid_gid(vector_t *strvec, unsigned keyword_offset, uid_t *uid_p, gid_t *gid_p)
00db14
-{
00db14
-	char *username;
00db14
-	char *groupname;
00db14
-	uid_t uid;
00db14
-	gid_t gid;
00db14
-	struct passwd pwd;
00db14
-	struct passwd *pwd_p;
00db14
-	struct group grp;
00db14
-	struct group *grp_p;
00db14
-	int ret;
00db14
-	char buf[getpwnam_buf_len];
00db14
-
00db14
-	username = strvec_slot(strvec, keyword_offset);
00db14
-
00db14
-	if ((ret = getpwnam_r(username, &pwd, buf, sizeof(buf), &pwd_p))) {
00db14
-		log_message(LOG_INFO, "Unable to resolve script username '%s' - ignoring", username);
00db14
-		return true;
00db14
-	}
00db14
-	if (!pwd_p) {
00db14
-		log_message(LOG_INFO, "Script user '%s' does not exist", username);
00db14
-		return true;
00db14
-	}
00db14
-
00db14
-	uid = pwd.pw_uid;
00db14
-	gid = pwd.pw_gid;
00db14
-
00db14
-	if (vector_size(strvec) > keyword_offset + 1) {
00db14
-		groupname = strvec_slot(strvec, keyword_offset + 1);
00db14
-		if ((ret = getgrnam_r(groupname, &grp, buf, sizeof(buf), &grp_p))) {
00db14
-			log_message(LOG_INFO, "Unable to resolve script group name '%s' - ignoring", groupname);
00db14
-			return true;
00db14
-		}
00db14
-		if (!grp_p) {
00db14
-			log_message(LOG_INFO, "Script group '%s' does not exist", groupname);
00db14
-			return true;
00db14
-		}
00db14
-		gid = grp.gr_gid;
00db14
-	}
00db14
-
00db14
-	*uid_p = uid;
00db14
-	*gid_p = gid;
00db14
-
00db14
-	return false;
00db14
-}
00db14
-
00db14
 static void
00db14
 script_user_handler(vector_t *strvec)
00db14
 {
00db14
@@ -756,7 +709,7 @@ script_user_handler(vector_t *strvec)
00db14
 		return;
00db14
 	}
00db14
 
00db14
-	if (set_script_uid_gid(strvec, 1, &default_script_uid, &default_script_gid))
00db14
+	if (set_default_script_user(strvec_slot(strvec, 1), vector_size(strvec) > 2 ? strvec_slot(strvec, 2) : NULL, true))
00db14
 		log_message(LOG_INFO, "Error setting global script uid/gid");
00db14
 }
00db14
 
00db14
diff --git a/keepalived/core/main.c b/keepalived/core/main.c
00db14
index 55eb263..95bb76a 100644
00db14
--- a/keepalived/core/main.c
00db14
+++ b/keepalived/core/main.c
00db14
@@ -119,6 +119,9 @@ free_parent_mallocs_startup(bool am_child)
00db14
 #else
00db14
 		free(syslog_ident);
00db14
 #endif
00db14
+
00db14
+		if (orig_core_dump_pattern)
00db14
+			FREE_PTR(orig_core_dump_pattern);
00db14
 	}
00db14
 
00db14
 	if (free_main_pidfile) {
00db14
@@ -765,7 +768,6 @@ keepalived_main(int argc, char **argv)
00db14
 	bool report_stopped = true;
00db14
 	struct utsname uname_buf;
00db14
 	char *end;
00db14
-	long buf_len;
00db14
 
00db14
 	/* Init debugging level */
00db14
 	debug = 0;
00db14
@@ -814,17 +816,6 @@ keepalived_main(int argc, char **argv)
00db14
 
00db14
 	netlink_set_recv_buf_size();
00db14
 
00db14
-	set_default_script_user(&default_script_uid, &default_script_gid);
00db14
-
00db14
-	/* Get buffer length needed for getpwnam_r/getgrnam_r */
00db14
-	if ((buf_len = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1)
00db14
-		getpwnam_buf_len = 1024;	/* A safe default if no value is returned */
00db14
-	else
00db14
-		getpwnam_buf_len = (size_t)buf_len;
00db14
-	if ((buf_len = sysconf(_SC_GETGR_R_SIZE_MAX)) != -1 &&
00db14
-	    (size_t)buf_len > getpwnam_buf_len)
00db14
-		getpwnam_buf_len = (size_t)buf_len;
00db14
-
00db14
 	/* Some functionality depends on kernel version, so get the version here */
00db14
 	if (uname(&uname_buf))
00db14
 		log_message(LOG_INFO, "Unable to get uname() information - error %d", errno);
00db14
diff --git a/keepalived/include/check_misc.h b/keepalived/include/check_misc.h
00db14
index ed0d962..ec97149 100644
00db14
--- a/keepalived/include/check_misc.h
00db14
+++ b/keepalived/include/check_misc.h
00db14
@@ -36,7 +36,7 @@
00db14
 typedef struct _misc_checker {
00db14
 	char			*path;
00db14
 	unsigned long		timeout;
00db14
-	int			dynamic;	/* 0: old-style, 1: exit code from checker affects weight */
00db14
+	bool			dynamic;	/* false: old-style, true: exit code from checker affects weight */
00db14
 	bool			forcing_termination; /* Set if we have sent the process a SIGTERM */
00db14
 	uid_t			uid;		/* uid for script execution */
00db14
 	gid_t			gid;		/* gid for script execution */
00db14
diff --git a/keepalived/include/main.h b/keepalived/include/main.h
00db14
index d125566..eebde77 100644
00db14
--- a/keepalived/include/main.h
00db14
+++ b/keepalived/include/main.h
00db14
@@ -73,8 +73,6 @@ extern bool namespace_with_ipsets;	/* override for namespaces with ipsets on Lin
00db14
 #endif
00db14
 extern char *instance_name;		/* keepalived instance name */
00db14
 extern bool use_pid_dir;		/* pid files in /var/run/keepalived */
00db14
-extern uid_t default_script_uid;	/* Default user/group for script execution */
00db14
-extern gid_t default_script_gid;
00db14
 extern unsigned os_major;		/* Kernel version */
00db14
 extern unsigned os_minor;
00db14
 extern unsigned os_release;
00db14
diff --git a/keepalived/vrrp/vrrp_data.c b/keepalived/vrrp/vrrp_data.c
00db14
index 76f17a4..b5c59df 100644
00db14
--- a/keepalived/vrrp/vrrp_data.c
00db14
+++ b/keepalived/vrrp/vrrp_data.c
00db14
@@ -160,8 +160,7 @@ dump_vscript(void *data)
00db14
 		str = (vscript->result >= vscript->rise) ? "GOOD" : "BAD";
00db14
 	}
00db14
 	log_message(LOG_INFO, "   Status = %s", str);
00db14
-	if (vscript->uid || vscript->gid)
00db14
-		log_message(LOG_INFO, "   Script uid:gid = %d:%d", vscript->uid, vscript->gid);
00db14
+	log_message(LOG_INFO, "   Script uid:gid = %d:%d", vscript->uid, vscript->gid);
00db14
 
00db14
 }
00db14
 
00db14
diff --git a/keepalived/vrrp/vrrp_parser.c b/keepalived/vrrp/vrrp_parser.c
00db14
index 7a38315..c774dec 100644
00db14
--- a/keepalived/vrrp/vrrp_parser.c
00db14
+++ b/keepalived/vrrp/vrrp_parser.c
00db14
@@ -48,6 +48,9 @@
00db14
 #include "bitops.h"
00db14
 #include "notify.h"
00db14
 
00db14
+static bool script_user_set;
00db14
+static bool remove_script;
00db14
+
00db14
 /* Static addresses handler */
00db14
 static void
00db14
 static_addresses_handler(__attribute__((unused)) vector_t *strvec)
00db14
@@ -120,14 +123,7 @@ vrrp_group_handler(vector_t *strvec)
00db14
 static inline notify_script_t*
00db14
 set_vrrp_notify_script(vector_t *strvec)
00db14
 {
00db14
-	notify_script_t *script = notify_script_init(strvec, default_script_uid, default_script_gid);
00db14
-
00db14
-	if (vector_size(strvec) > 2) {
00db14
-		if (set_script_uid_gid(strvec, 2, &script->uid, &script->gid))
00db14
-			log_message(LOG_INFO, "Invalid user/group for notify script %s", script->name);
00db14
-	}
00db14
-
00db14
-	return script;
00db14
+	return notify_script_init(strvec, "notify", global_data->script_security);
00db14
 }
00db14
 
00db14
 static void
00db14
@@ -680,6 +676,8 @@ static void
00db14
 vrrp_script_handler(vector_t *strvec)
00db14
 {
00db14
 	alloc_vrrp_script(strvec_slot(strvec, 1));
00db14
+	script_user_set = false;
00db14
+	remove_script = false;
00db14
 }
00db14
 static void
00db14
 vrrp_vscript_script_handler(vector_t *strvec)
00db14
@@ -731,8 +729,35 @@ static void
00db14
 vrrp_vscript_user_handler(vector_t *strvec)
00db14
 {
00db14
 	vrrp_script_t *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script);
00db14
-	if (set_script_uid_gid(strvec, 1, &vscript->uid, &vscript->gid))
00db14
-		log_message(LOG_INFO, "Unable to set uid/gid for script %s", vscript->script);
00db14
+	if (set_script_uid_gid(strvec, 1, &vscript->uid, &vscript->gid)) {
00db14
+		log_message(LOG_INFO, "Unable to set uid/gid for script %s - disabling", vscript->script);
00db14
+		remove_script = true;
00db14
+	}
00db14
+	else
00db14
+		script_user_set = true;
00db14
+}
00db14
+static void
00db14
+vrrp_vscript_end_handler(void)
00db14
+{
00db14
+	vrrp_script_t *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script);
00db14
+
00db14
+	if (script_user_set)
00db14
+		return;
00db14
+
00db14
+	if (!remove_script &&
00db14
+	     set_default_script_user(NULL, NULL, global_data->script_security)) {
00db14
+		log_message(LOG_INFO, "Unable to set default user for track script %s - removing", vscript->script);
00db14
+		remove_script = true;
00db14
+	}
00db14
+
00db14
+	if (remove_script) {
00db14
+		free_list_element(vrrp_data->vrrp_script, vrrp_data->vrrp_script->tail);
00db14
+		return;
00db14
+	}
00db14
+
00db14
+	vscript->uid = default_script_uid;
00db14
+	vscript->gid = default_script_gid;
00db14
+
00db14
 }
00db14
 static void
00db14
 vrrp_vscript_init_fail_handler(__attribute__((unused)) vector_t *strvec)
00db14
@@ -964,6 +989,7 @@ init_vrrp_keywords(bool active)
00db14
 	install_keyword("fall", &vrrp_vscript_fall_handler);
00db14
 	install_keyword("user", &vrrp_vscript_user_handler);
00db14
 	install_keyword("init_fail", &vrrp_vscript_init_fail_handler);
00db14
+	install_sublevel_end_handler(&vrrp_vscript_end_handler);
00db14
 }
00db14
 
00db14
 vector_t *
00db14
diff --git a/keepalived/vrrp/vrrp_print.c b/keepalived/vrrp/vrrp_print.c
00db14
index 7adb701..54da044 100644
00db14
--- a/keepalived/vrrp/vrrp_print.c
00db14
+++ b/keepalived/vrrp/vrrp_print.c
00db14
@@ -92,6 +92,7 @@ vscript_print(FILE *file, void *data)
00db14
 	fprintf(file, "   Rise = %d\n", vscript->rise);
00db14
 	fprintf(file, "   Full = %d\n", vscript->fall);
00db14
 	fprintf(file, "   Insecure = %s\n", vscript->insecure ? "yes" : "no");
00db14
+	fprintf(file, "   uid:gid = %d:%d\n", vscript->uid, vscript->gid);
00db14
 
00db14
 	switch (vscript->result) {
00db14
 	case VRRP_SCRIPT_STATUS_INIT:
00db14
diff --git a/lib/notify.c b/lib/notify.c
00db14
index d92c50d..a8742fe 100644
00db14
--- a/lib/notify.c
00db14
+++ b/lib/notify.c
00db14
@@ -44,10 +44,15 @@
00db14
 #include "vector.h"
00db14
 #include "parser.h"
00db14
 
00db14
-size_t getpwnam_buf_len;				/* Buffer length needed for getpwnam_r/getgrname_r */
00db14
 
00db14
+uid_t default_script_uid;				/* Default user/group for script execution */
00db14
+gid_t default_script_gid;
00db14
+static bool default_script_uid_set = false;
00db14
+static bool default_user_fail = false;			/* Set if failed to set default user,
00db14
+							   unless it defaults to root */
00db14
 static char *path;
00db14
 static bool path_is_malloced;
00db14
+static size_t getpwnam_buf_len;				/* Buffer length needed for getpwnam_r/getgrname_r */
00db14
 
00db14
 /* perform a system call */
00db14
 static int
00db14
@@ -565,40 +570,135 @@ check_notify_script_secure(notify_script_t **script_p, bool script_security, boo
00db14
 	return flags;
00db14
 }
00db14
 
00db14
-/* The default script user/group is keepalived_script if it exists, or root otherwise */
00db14
-void
00db14
-set_default_script_user(uid_t *uid, gid_t *gid)
00db14
+static void
00db14
+set_pwnam_buf_len(void)
00db14
+{
00db14
+	long buf_len;
00db14
+
00db14
+	/* Get buffer length needed for getpwnam_r/getgrnam_r */
00db14
+	if ((buf_len = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1)
00db14
+		getpwnam_buf_len = 1024;	/* A safe default if no value is returned */
00db14
+	else
00db14
+		getpwnam_buf_len = (size_t)buf_len;
00db14
+	if ((buf_len = sysconf(_SC_GETGR_R_SIZE_MAX)) != -1 &&
00db14
+	    (size_t)buf_len > getpwnam_buf_len)
00db14
+		getpwnam_buf_len = (size_t)buf_len;
00db14
+}
00db14
+
00db14
+bool
00db14
+set_uid_gid(const char *username, const char *groupname, uid_t *uid_p, gid_t *gid_p, bool default_user)
00db14
 {
00db14
-	char buf[getpwnam_buf_len];
00db14
-	char *default_user_name = "keepalived_script";
00db14
+	uid_t uid;
00db14
+	gid_t gid;
00db14
 	struct passwd pwd;
00db14
 	struct passwd *pwd_p;
00db14
+	struct group grp;
00db14
+	struct group *grp_p;
00db14
+	int ret;
00db14
+	bool using_default_default_user = false;
00db14
+
00db14
+	if (!getpwnam_buf_len)
00db14
+		set_pwnam_buf_len();
00db14
 
00db14
-	if (getpwnam_r(default_user_name, &pwd, buf, sizeof(buf), &pwd_p)) {
00db14
-		log_message(LOG_INFO, "Unable to resolve default script username '%s' - ignoring", default_user_name);
00db14
-		return;
00db14
+	{
00db14
+		char buf[getpwnam_buf_len];
00db14
+
00db14
+		if (default_user && !username) {
00db14
+			using_default_default_user = true;
00db14
+			username = "keepalived_script";
00db14
+		}
00db14
+
00db14
+		if ((ret = getpwnam_r(username, &pwd, buf, sizeof(buf), &pwd_p))) {
00db14
+			log_message(LOG_INFO, "Unable to resolve %sscript username '%s' - ignoring", default_user ? "default " : "", username);
00db14
+			return true;
00db14
+		}
00db14
+		if (!pwd_p) {
00db14
+			if (using_default_default_user)
00db14
+				log_message(LOG_INFO, "WARNING - default user '%s' for script execution does not exist - please create.", username);
00db14
+			else
00db14
+				log_message(LOG_INFO, "%script user '%s' does not exist", default_user ? "Default s" : "S", username);
00db14
+			return true;
00db14
+		}
00db14
+
00db14
+		uid = pwd.pw_uid;
00db14
+		gid = pwd.pw_gid;
00db14
+
00db14
+		if (groupname) {
00db14
+			if ((ret = getgrnam_r(groupname, &grp, buf, sizeof(buf), &grp_p))) {
00db14
+				log_message(LOG_INFO, "Unable to resolve %sscript group name '%s' - ignoring", default_user ? "default " : "", groupname);
00db14
+				return true;
00db14
+			}
00db14
+			if (!grp_p) {
00db14
+				log_message(LOG_INFO, "%script group '%s' does not exist", default_user ? "Default s" : "S", groupname);
00db14
+				return true;
00db14
+			}
00db14
+			gid = grp.gr_gid;
00db14
+		}
00db14
+
00db14
+		*uid_p = uid;
00db14
+		*gid_p = gid;
00db14
 	}
00db14
-	if (!pwd_p) {
00db14
-		/* The username does not exist */
00db14
-		log_message(LOG_INFO, "WARNING - default user '%s' for script execution does not exist - please create.", default_user_name);
00db14
-		return;
00db14
+
00db14
+	return false;
00db14
+}
00db14
+
00db14
+bool
00db14
+set_default_script_user(const char *username, const char *groupname, bool script_security)
00db14
+{
00db14
+	if (!default_script_uid_set || username) {
00db14
+		/* Even if we fail to set it, there is no point in trying again */
00db14
+		default_script_uid_set = true;
00db14
+
00db14
+		if (set_uid_gid(username, groupname, &default_script_uid, &default_script_gid, true)) {
00db14
+			if (username || script_security)
00db14
+				default_user_fail = true;
00db14
+		}
00db14
+		else
00db14
+			default_user_fail = false;
00db14
 	}
00db14
 
00db14
-	*uid = pwd.pw_uid;
00db14
-	*gid = pwd.pw_gid;
00db14
+	return default_user_fail;
00db14
+}
00db14
+
00db14
+bool
00db14
+set_script_uid_gid(vector_t *strvec, unsigned keyword_offset, uid_t *uid_p, gid_t *gid_p)
00db14
+{
00db14
+	char *username;
00db14
+	char *groupname;
00db14
+
00db14
+	username = strvec_slot(strvec, keyword_offset);
00db14
+	if (vector_size(strvec) > keyword_offset + 1)
00db14
+		groupname = strvec_slot(strvec, keyword_offset + 1);
00db14
+	else
00db14
+		groupname = NULL;
00db14
 
00db14
-	log_message(LOG_INFO, "Setting default script user to '%s', uid:gid %d:%d", default_user_name, pwd.pw_uid, pwd.pw_gid);
00db14
+	return set_uid_gid(username, groupname, uid_p, gid_p, false);
00db14
 }
00db14
 
00db14
 notify_script_t*
00db14
-notify_script_init(vector_t *strvec, uid_t uid, gid_t gid)
00db14
+notify_script_init(vector_t *strvec, const char *type, bool script_security)
00db14
 {
00db14
 	notify_script_t *script = MALLOC(sizeof(notify_script_t));
00db14
 
00db14
 	script->name = set_value(strvec);
00db14
-	script->uid = uid;
00db14
-	script->gid = gid;
00db14
+
00db14
+	if (vector_size(strvec) > 2) {
00db14
+		if (set_script_uid_gid(strvec, 2, &script->uid, &script->gid)) {
00db14
+			log_message(LOG_INFO, "Invalid user/group for %s script %s - ignoring", type, script->name);
00db14
+			FREE(script);
00db14
+			return NULL;
00db14
+		}
00db14
+        }
00db14
+	else {
00db14
+		if (set_default_script_user(NULL, NULL, script_security)) {
00db14
+			log_message(LOG_INFO, "Failed to set default user for %s script %s - ignoring", type, script->name);
00db14
+			FREE(script);
00db14
+			return NULL;
00db14
+		}
00db14
+
00db14
+		script->uid = default_script_uid;
00db14
+		script->gid = default_script_gid;
00db14
+	}
00db14
 
00db14
 	return script;
00db14
 }
00db14
-
00db14
diff --git a/lib/notify.h b/lib/notify.h
00db14
index ac07edb..3d092ea 100644
00db14
--- a/lib/notify.h
00db14
+++ b/lib/notify.h
00db14
@@ -56,7 +56,8 @@ free_notify_script(notify_script_t **script)
00db14
 }
00db14
 
00db14
 /* Global variables */
00db14
-extern size_t getpwnam_buf_len;		/* Buffer length needed for getpwnam_r/getgrnam_r */
00db14
+extern uid_t default_script_uid;        /* Default user/group for script execution */
00db14
+extern gid_t default_script_gid;
00db14
 
00db14
 /* prototypes */
00db14
 extern int system_call_script(thread_master_t *, int (*) (thread_t *), void *, unsigned long, const char*, uid_t, gid_t);
00db14
@@ -64,7 +65,7 @@ extern int notify_exec(const notify_script_t *);
00db14
 extern void script_killall(thread_master_t *, int);
00db14
 extern int check_script_secure(notify_script_t *, bool, bool);
00db14
 extern int check_notify_script_secure(notify_script_t **, bool, bool);
00db14
-extern void set_default_script_user(uid_t *, gid_t *);
00db14
-extern notify_script_t* notify_script_init(vector_t *, uid_t, gid_t);
00db14
+extern bool set_default_script_user(const char *, const char *, bool);
00db14
+extern notify_script_t* notify_script_init(vector_t *, const char *, bool);
00db14
 
00db14
 #endif
00db14
-- 
00db14
2.9.4
00db14