heads up: tcpwrappers support going away
Damien Miller
djm at mindrot.org
Thu Apr 24 08:58:02 EST 2014
On Wed, 23 Apr 2014, Damien Miller wrote:
> A simple way out of this would be adding "Match exec" support to sshd_config
> like ssh_config got in the last couple of releases. Anyone want to do this?
like this:
Index: servconf.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/servconf.c,v
retrieving revision 1.249
diff -u -p -r1.249 servconf.c
--- servconf.c 29 Jan 2014 06:18:35 -0000 1.249
+++ servconf.c 23 Apr 2014 22:56:54 -0000
@@ -50,6 +50,7 @@
#include "packet.h"
#include "hostfile.h"
#include "auth.h"
+#include "misc.h"
static void add_listen_addr(ServerOptions *, char *, int);
static void add_one_listen_addr(ServerOptions *, char *, int);
@@ -604,9 +605,10 @@ out:
static int
match_cfg_line(char **condition, int line, struct connection_info *ci)
{
- int result = 1, attributes = 0, port;
- char *arg, *attrib, *cp = *condition;
+ int r, result = 1, attributes = 0, port;
+ char *arg, *attrib, *cmd, *cp = *condition;
size_t len;
+ char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
if (ci == NULL)
debug3("checking syntax for 'Match %s'", cp);
@@ -717,6 +719,45 @@ match_cfg_line(char **condition, int lin
ci->laddress, port, line);
else
result = 0;
+ } else if (strcasecmp(attrib, "exec") == 0) {
+ if (ci == NULL) {
+ result = 0;
+ continue;
+ }
+ if (gethostname(thishost, sizeof(thishost)) == -1)
+ fatal("gethostname: %s", strerror(errno));
+ strlcpy(shorthost, thishost, sizeof(shorthost));
+ shorthost[strcspn(thishost, ".")] = '\0';
+ snprintf(portstr, sizeof(portstr), "%d", ci->lport);
+
+ cmd = percent_expand(arg,
+ "L", shorthost,
+ "l", thishost,
+ "h", ci->host,
+ "P", portstr,
+ "u", ci->user,
+ "a", ci->address,
+ "A", ci->laddress,
+ (char *)NULL);
+ if (result != 1) {
+ /* skip execution if prior predicate failed */
+ debug("config line %d: skipped exec \"%.100s\"",
+ line, cmd);
+ } else {
+ r = execute_in_shell(cmd, 0);
+ if (r == -1) {
+ fatal("config line %d: match exec "
+ "'%.100s' error", line, cmd);
+ } else if (r == 0) {
+ debug("config line %d: matched "
+ "'exec \"%.100s\"'", line, cmd);
+ } else {
+ debug("config line %d: no match "
+ "'exec \"%.100s\"'", line, cmd);
+ result = 0;
+ }
+ }
+ free(cmd);
} else {
error("Unsupported Match attribute %s", attrib);
return -1;
Index: readconf.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/readconf.c,v
retrieving revision 1.219
diff -u -p -r1.219 readconf.c
--- readconf.c 23 Apr 2014 12:42:34 -0000 1.219
+++ readconf.c 23 Apr 2014 22:56:55 -0000
@@ -15,7 +15,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
-#include <sys/wait.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -27,7 +26,6 @@
#include <netdb.h>
#include <paths.h>
#include <pwd.h>
-#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@@ -46,7 +44,6 @@
#include "buffer.h"
#include "kex.h"
#include "mac.h"
-#include "uidswap.h"
/* Format of the configuration file:
@@ -376,80 +373,6 @@ default_ssh_port(void)
}
/*
- * Execute a command in a shell.
- * Return its exit status or -1 on abnormal exit.
- */
-static int
-execute_in_shell(const char *cmd)
-{
- char *shell, *command_string;
- pid_t pid;
- int devnull, status;
- extern uid_t original_real_uid;
-
- if ((shell = getenv("SHELL")) == NULL)
- shell = _PATH_BSHELL;
-
- /*
- * Use "exec" to avoid "sh -c" processes on some platforms
- * (e.g. Solaris)
- */
- xasprintf(&command_string, "exec %s", cmd);
-
- /* Need this to redirect subprocess stdin/out */
- if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
- fatal("open(/dev/null): %s", strerror(errno));
-
- debug("Executing command: '%.500s'", cmd);
-
- /* Fork and execute the command. */
- if ((pid = fork()) == 0) {
- char *argv[4];
-
- /* Child. Permanently give up superuser privileges. */
- permanently_drop_suid(original_real_uid);
-
- /* Redirect child stdin and stdout. Leave stderr */
- if (dup2(devnull, STDIN_FILENO) == -1)
- fatal("dup2: %s", strerror(errno));
- if (dup2(devnull, STDOUT_FILENO) == -1)
- fatal("dup2: %s", strerror(errno));
- if (devnull > STDERR_FILENO)
- close(devnull);
- closefrom(STDERR_FILENO + 1);
-
- argv[0] = shell;
- argv[1] = "-c";
- argv[2] = command_string;
- argv[3] = NULL;
-
- execv(argv[0], argv);
- error("Unable to execute '%.100s': %s", cmd, strerror(errno));
- /* Die with signal to make this error apparent to parent. */
- signal(SIGTERM, SIG_DFL);
- kill(getpid(), SIGTERM);
- _exit(1);
- }
- /* Parent. */
- if (pid < 0)
- fatal("%s: fork: %.100s", __func__, strerror(errno));
-
- close(devnull);
- free(command_string);
-
- while (waitpid(pid, &status, 0) == -1) {
- if (errno != EINTR && errno != EAGAIN)
- fatal("%s: waitpid: %s", __func__, strerror(errno));
- }
- if (!WIFEXITED(status)) {
- error("command '%.100s' exited abnormally", cmd);
- return -1;
- }
- debug3("command returned status %d", WEXITSTATUS(status));
- return WEXITSTATUS(status);
-}
-
-/*
* Parse and execute a Match directive.
*/
static int
@@ -461,6 +384,7 @@ match_cfg_line(Options *options, char **
int r, port, result = 1, attributes = 0;
size_t len;
char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
+ extern uid_t original_real_uid;
/*
* Configuration is likely to be incomplete at this point so we
@@ -544,7 +468,7 @@ match_cfg_line(Options *options, char **
debug("%.200s line %d: skipped exec \"%.100s\"",
filename, linenum, cmd);
} else {
- r = execute_in_shell(cmd);
+ r = execute_in_shell(cmd, original_real_uid);
if (r == -1) {
fatal("%.200s line %d: match exec "
"'%.100s' error", filename,
Index: misc.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/misc.c,v
retrieving revision 1.93
diff -u -p -r1.93 misc.c
--- misc.c 20 Apr 2014 02:30:25 -0000 1.93
+++ misc.c 23 Apr 2014 22:56:55 -0000
@@ -28,6 +28,7 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/param.h>
+#include <sys/wait.h>
#include <net/if.h>
#include <netinet/in.h>
@@ -41,6 +42,7 @@
#include <netdb.h>
#include <paths.h>
#include <pwd.h>
+#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -1019,3 +1021,80 @@ lowercase(char *s)
for (; *s; s++)
*s = tolower((u_char)*s);
}
+
+/*
+ * Execute a command in a shell.
+ * Return its exit status or -1 on abnormal exit.
+ */
+int
+execute_in_shell(const char *cmd, uid_t drop_uid)
+{
+ char *shell, *command_string;
+ pid_t pid;
+ int devnull, status;
+
+ if ((shell = getenv("SHELL")) == NULL)
+ shell = _PATH_BSHELL;
+
+ /*
+ * Use "exec" to avoid "sh -c" processes on some platforms
+ * (e.g. Solaris)
+ */
+ xasprintf(&command_string, "exec %s", cmd);
+
+ /* Need this to redirect subprocess stdin/out */
+ if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
+ fatal("open(/dev/null): %s", strerror(errno));
+
+ debug("Executing command: '%.500s'", cmd);
+
+ /* Fork and execute the command. */
+ if ((pid = fork()) == 0) {
+ char *argv[4];
+
+ /* Child. Permanently give up superuser privileges. */
+ if (drop_uid != 0 &&
+ setresuid(drop_uid, drop_uid, drop_uid) != 0)
+ fatal("%s: setresuid %lu: %s", __func__,
+ (u_long)drop_uid, strerror(errno));
+
+ /* Redirect child stdin and stdout. Leave stderr */
+ if (dup2(devnull, STDIN_FILENO) == -1)
+ fatal("dup2: %s", strerror(errno));
+ if (dup2(devnull, STDOUT_FILENO) == -1)
+ fatal("dup2: %s", strerror(errno));
+ if (devnull > STDERR_FILENO)
+ close(devnull);
+ closefrom(STDERR_FILENO + 1);
+
+ argv[0] = shell;
+ argv[1] = "-c";
+ argv[2] = command_string;
+ argv[3] = NULL;
+
+ execv(argv[0], argv);
+ error("Unable to execute '%.100s': %s", cmd, strerror(errno));
+ /* Die with signal to make this error apparent to parent. */
+ signal(SIGTERM, SIG_DFL);
+ kill(getpid(), SIGTERM);
+ _exit(1);
+ }
+ /* Parent. */
+ if (pid < 0)
+ fatal("%s: fork: %.100s", __func__, strerror(errno));
+
+ close(devnull);
+ free(command_string);
+
+ while (waitpid(pid, &status, 0) == -1) {
+ if (errno != EINTR && errno != EAGAIN)
+ fatal("%s: waitpid: %s", __func__, strerror(errno));
+ }
+ if (!WIFEXITED(status)) {
+ error("command '%.100s' exited abnormally", cmd);
+ return -1;
+ }
+ debug3("command returned status %d", WEXITSTATUS(status));
+ return WEXITSTATUS(status);
+}
+
Index: misc.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/misc.h,v
retrieving revision 1.52
diff -u -p -r1.52 misc.h
--- misc.h 20 Apr 2014 02:30:25 -0000 1.52
+++ misc.h 23 Apr 2014 22:56:55 -0000
@@ -37,6 +37,7 @@ void ms_subtract_diff(struct timeval *,
void ms_to_timeval(struct timeval *, int);
time_t monotime(void);
void lowercase(char *s);
+int execute_in_shell(const char *, uid_t);
struct passwd *pwcopy(struct passwd *);
const char *ssh_gai_strerror(int);
More information about the openssh-unix-dev
mailing list