[patch] nsca chroot() support

sean finney seanius at seanius.net
Sun Mar 12 12:00:32 CET 2006


hi ethan et al,

attached is a an initial patch which gives nsca the ability to
perform a chroot() before dropping privileges when in daemon
mode.  the patch basically does the following:

- provide a new nsca.cfg option nsca_chroot_dir
- split the drop_privileges function into two logical parts:  the part
  that gets the user/group info and the part that actually does the
  dropping.  this is necessary because in most cases it's impossible
  to get the user/group info after chrooting, and chrooting needs to
  be done before privileges are dropped.
- introduce a do_chroot function which uh, does the chrooting if the
  configuration option is specified.  nsca exits with an error if the
  chroot fails.

also, while making this patch, i've noticed the following:

- there seems to be a mishmash of spaces and tabs used for indentation.
  which should i use?  i fear i have only added to the mishmash but
  have tried to minimize the size of the diff at least.
- currently nsca does not exit with an error if it fails to drop
  privileges.  is this intentional?


anyway, please let me know if you see any issues with this patch.


thanks,
	sean
-------------- next part --------------
#! /bin/sh /usr/share/dpatch/dpatch-run
## 05_nsca_chroot.dpatch by  <seanius at debian.org>
##
## DP: provide support for chrooting when in daemon mode.

@DPATCH@
diff -urNad --exclude=CVS --exclude=.svn ./sample-config/nsca.cfg.in /home/sean/tmp/dpep-work.v8Tmq4/nsca-2.5/sample-config/nsca.cfg.in
--- ./sample-config/nsca.cfg.in	2006-03-12 11:40:20.000000000 +0100
+++ /home/sean/tmp/dpep-work.v8Tmq4/nsca-2.5/sample-config/nsca.cfg.in	2006-03-12 11:40:20.000000000 +0100
@@ -42,6 +42,16 @@
 
 nsca_group=@nsca_grp@
 
+# NSCA CHROOT
+# If specified, determines a directory into which the nsca daemon
+# will perform a chroot(2) operation before dropping its privileges.
+# for the security conscious this can add a layer of protection in
+# the event that the nagios daemon is compromised.  
+# 
+# NOTE: if you specify this option, the command file will be opened
+#       relative to this directory.
+
+#nsca_chroot=/var/run/nagios/rw
 
 
 # DEBUGGING OPTION
diff -urNad --exclude=CVS --exclude=.svn ./src/nsca.c /home/sean/tmp/dpep-work.v8Tmq4/nsca-2.5/src/nsca.c
--- ./src/nsca.c	2006-03-12 11:40:20.000000000 +0100
+++ /home/sean/tmp/dpep-work.v8Tmq4/nsca-2.5/src/nsca.c	2006-03-12 11:41:50.000000000 +0100
@@ -40,8 +40,11 @@
 static int open_command_file(void);
 static void close_command_file(void);
 static void install_child_handler(void);
-static int drop_privileges(char *,char *);
+static int get_user_info(const char *, uid_t *);
+static int get_group_info(const char *, gid_t *);
+static int drop_privileges(const char *,uid_t,gid_t);
 static int write_check_result(char *,char *,int,char *,time_t);
+static void do_chroot(void);
 static void do_exit(int);
 
 static enum { OPTIONS_ERROR, SINGLE_PROCESS_DAEMON, MULTI_PROCESS_DAEMON, INETD } mode=SINGLE_PROCESS_DAEMON;
@@ -54,6 +57,8 @@
 char *nsca_user=NULL;
 char *nsca_group=NULL;
 
+char *nsca_chroot=NULL;
+
 int show_help=FALSE;
 int show_license=FALSE;
 int show_version=FALSE;
@@ -88,6 +93,8 @@
 int main(int argc, char **argv){
         char buffer[MAX_INPUT_BUFFER];
         int result;
+        uid_t uid=-1;
+        gid_t gid=-1;
 
 
 	/* process command-line arguments */
@@ -143,7 +150,7 @@
 
 
         /* open a connection to the syslog facility */
-        openlog("nsca",LOG_PID,LOG_DAEMON); 
+        openlog("nsca",LOG_PID|LOG_NDELAY,LOG_DAEMON); 
 
 	/* make sure the config file uses an absolute path */
 	if(config_file[0]!='/'){
@@ -180,6 +187,9 @@
         switch(mode){
 
         case INETD:
+				/* chroot if configured */
+				do_chroot();
+
                 /* if we're running under inetd, handle one connection and get out */
                 handle_connection(0,NULL);
                 break;
@@ -209,8 +219,15 @@
 			open("/dev/null",O_WRONLY);
 			open("/dev/null",O_WRONLY);
 
+			/* get group information before chrooting */
+			get_user_info(nsca_user, &uid);
+			get_group_info(nsca_group, &gid);
+
+			/* chroot if configured */
+			do_chroot();
+
 			/* drop privileges */
-			drop_privileges(nsca_user,nsca_group);
+			drop_privileges(nsca_user,uid,gid);
 
                         /* wait for connections */
                         wait_for_connections();
@@ -411,6 +428,9 @@
                 else if(!strcmp(varname,"nsca_group"))
 			nsca_group=strdup(varvalue);
 
+                else if(!strcmp(varname,"nsca_chroot"))
+			nsca_chroot=strdup(varvalue);
+
 		else{
                         syslog(LOG_ERR,"Unknown option specified in config file '%s' - Line %d\n",filename,line);
 
@@ -1144,62 +1164,71 @@
 	return OK;
         }
 
+/* get user information */
+static int get_user_info(const char *user, uid_t *uid){
+	const struct passwd *pw=NULL;
+	
+	if(user!=NULL){
+		/* see if this is a user name */
+		if(strspn(user,"0123456789")<strlen(user)){
+			pw=(struct passwd *)getpwnam(user);
+			if(pw!=NULL)
+				*uid=(uid_t)(pw->pw_uid);
+			else
+				syslog(LOG_ERR,"Warning: Could not get passwd entry for '%s'",user);
+			endpwent();
+		}
 
+		/* else we were passed the UID */
+		else
+			*uid=(uid_t)atoi(user);
 
-/* drops privileges */
-static int drop_privileges(char *user, char *group){
-	uid_t uid=-1;
-	gid_t gid=-1;
-	struct group *grp;
-	struct passwd *pw;
+	} else
+		*uid=geteuid();
 
-	/* set effective group ID */
+	return OK;
+}
+
+
+/* get group information */
+static int get_group_info(const char *group, gid_t *gid){
+	const struct group *grp=NULL;
+	
+	/* get group ID */
 	if(group!=NULL){
-		
 		/* see if this is a group name */
 		if(strspn(group,"0123456789")<strlen(group)){
 			grp=(struct group *)getgrnam(group);
 			if(grp!=NULL)
-				gid=(gid_t)(grp->gr_gid);
+				*gid=(gid_t)(grp->gr_gid);
 			else
 				syslog(LOG_ERR,"Warning: Could not get group entry for '%s'",group);
 			endgrent();
-		        }
+		}
 
 		/* else we were passed the GID */
 		else
-			gid=(gid_t)atoi(group);
+			*gid=(gid_t)atoi(group);
+	} else
+		*gid=getegid();
 
-		/* set effective group ID if other than current EGID */
-		if(gid!=getegid()){
+	return OK;
+}
 
-			if(setgid(gid)==-1)
-				syslog(LOG_ERR,"Warning: Could not set effective GID=%d",(int)gid);
-		        }
-	        }
 
+/* drops privileges */
+static int drop_privileges(const char *user, uid_t uid, gid_t gid){
+	struct group *grp;
+	struct passwd *pw;
 
-	/* set effective user ID */
-	if(user!=NULL){
-		
-		/* see if this is a user name */
-		if(strspn(user,"0123456789")<strlen(user)){
-			pw=(struct passwd *)getpwnam(user);
-			if(pw!=NULL)
-				uid=(uid_t)(pw->pw_uid);
-			else
-				syslog(LOG_ERR,"Warning: Could not get passwd entry for '%s'",user);
-			endpwent();
-		        }
+	/* set effective group ID if other than current EGID */
+	if(gid!=getegid()){
+		if(setgid(gid)==-1)
+			syslog(LOG_ERR,"Warning: Could not set effective GID=%d",(int)gid);
+	}
 
-		/* else we were passed the UID */
-		else
-			uid=(uid_t)atoi(user);
-			
 #ifdef HAVE_INITGROUPS
-
 		if(uid!=geteuid()){
-
 			/* initialize supplementary groups */
 			if(initgroups(user,gid)==-1){
 				if(errno==EPERM)
@@ -1207,14 +1236,34 @@
 				else{
 					syslog(LOG_ERR,"Warning: Possibly root user failed dropping privileges with initgroups()");
 					return ERROR;
-			                }
-	                        }
-		        }
+				}
+			}
+		}
 #endif
 
 		if(setuid(uid)==-1)
 			syslog(LOG_ERR,"Warning: Could not set effective UID=%d",(int)uid);
-	        }
 
-	return OK;
-        }
+		return OK;
+}
+
+/* perform the chroot() operation if configured to do so */
+void do_chroot(void){
+	int retval=0;
+	const char *err=NULL;
+
+	if(nsca_chroot != NULL){
+		retval=chdir(nsca_chroot);
+		if(retval!=0){
+			err=strerror(errno);
+			syslog(LOG_ERR, "can not chdir into chroot directory: %s", err);
+			do_exit(STATE_UNKNOWN);
+		}
+		retval=chroot(".");
+		if(retval!=0){
+			err=strerror(errno);
+			syslog(LOG_ERR, "can not chroot: %s", err);
+			do_exit(STATE_UNKNOWN);
+		}
+	}
+}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <https://www.monitoring-lists.org/archive/developers/attachments/20060312/4ae32859/attachment.sig>


More information about the Developers mailing list