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

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