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); _______________________________________________ openssh-unix-dev mailing list openssh-unix-dev@xxxxxxxxxxx https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev