diff dbutil.c @ 482:7ad49f34a122

- Add run_shell_command() function to run a "sh -c" command, handling lots of the work that exechild did (and can be shared by client -J option)
author Matt Johnston <matt@ucc.asn.au>
date Mon, 15 Sep 2008 14:04:55 +0000
parents 357a2e2e9bcc
children effb4a25b1ae
line wrap: on
line diff
--- a/dbutil.c	Mon Sep 15 13:41:18 2008 +0000
+++ b/dbutil.c	Mon Sep 15 14:04:55 2008 +0000
@@ -393,8 +393,7 @@
  * and the pid. exec_fn is the function that will actually execute the child process,
  * it will be run after the child has fork()ed, and is passed exec_data. */
 int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
-		int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid)
-{
+		int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid) {
 	int infds[2];
 	int outfds[2];
 	int errfds[2];
@@ -466,6 +465,48 @@
 	}
 }
 
+/* Runs a command with "sh -c". Will close FDs (except stdin/stdout/stderr) and
+ * re-enabled SIGPIPE. If cmd is NULL, will run a login shell.
+ */
+void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) {
+	char * argv[4];
+	char * baseshell = NULL;
+	unsigned int i;
+
+	baseshell = basename(usershell);
+
+	if (cmd != NULL) {
+		argv[0] = baseshell;
+	} else {
+		/* a login shell should be "-bash" for "/bin/bash" etc */
+		int len = strlen(baseshell) + 2; /* 2 for "-" */
+		argv[0] = (char*)m_malloc(len);
+		snprintf(argv[0], len, "-%s", baseshell);
+	}
+
+	if (cmd != NULL) {
+		argv[1] = "-c";
+		argv[2] = cmd;
+		argv[3] = NULL;
+	} else {
+		/* construct a shell of the form "-bash" etc */
+		argv[1] = NULL;
+	}
+
+	/* Re-enable SIGPIPE for the executed process */
+	if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) {
+		dropbear_exit("signal() error");
+	}
+
+	/* close file descriptors except stdin/stdout/stderr
+	 * Need to be sure FDs are closed here to avoid reading files as root */
+	for (i = 3; i <= maxfd; i++) {
+		m_close(i);
+	}
+
+	execv(usershell, argv);
+}
+
 /* Return a string representation of the socket address passed. The return
  * value is allocated with malloc() */
 unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {