config: Implement match exec keyword
The implementation does not work on Windows, where it still reports unsupported configuration option. On windows, separate code invoking subprocess needs to be implemented. Fixes T169 Signed-off-by: Jakub Jelen <jjelen@redhat.com> Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Этот коммит содержится в:
родитель
c7da113f1d
Коммит
c983c994a2
143
src/config.c
143
src/config.c
@ -32,6 +32,14 @@
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#ifndef _WIN32
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# include <fcntl.h>
|
||||
# include <errno.h>
|
||||
# include <signal.h>
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include "libssh/config_parser.h"
|
||||
#include "libssh/config.h"
|
||||
@ -287,6 +295,125 @@ ssh_config_match(char *value, const char *pattern, bool negate)
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static int
|
||||
ssh_match_exec(ssh_session session, const char *command, bool negate)
|
||||
{
|
||||
(void) session;
|
||||
(void) command;
|
||||
(void) negate;
|
||||
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unsupported 'exec' command on Windows '%s'",
|
||||
command);
|
||||
return 0;
|
||||
}
|
||||
#else /* _WIN32 */
|
||||
|
||||
static int
|
||||
ssh_exec_shell(char *cmd)
|
||||
{
|
||||
char *shell = NULL;
|
||||
pid_t pid;
|
||||
int status, devnull, rc;
|
||||
|
||||
shell = getenv("SHELL");
|
||||
if (shell == NULL || shell[0] == '\0') {
|
||||
shell = (char *)"/bin/sh";
|
||||
}
|
||||
|
||||
rc = access(shell, X_OK);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN, "The shell '%s' is not executable", shell);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Need this to redirect subprocess stdin/out */
|
||||
devnull = open("/dev/null", O_RDWR);
|
||||
if (devnull == -1) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Failed to open(/dev/null): %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Running command '%s'", cmd);
|
||||
pid = fork();
|
||||
if (pid == 0) { /* Child */
|
||||
char *argv[4];
|
||||
|
||||
/* Redirect child stdin and stdout. Leave stderr */
|
||||
rc = dup2(devnull, STDIN_FILENO);
|
||||
if (rc == -1) {
|
||||
SSH_LOG(SSH_LOG_WARN, "dup2: %s", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
rc = dup2(devnull, STDOUT_FILENO);
|
||||
if (rc == -1) {
|
||||
SSH_LOG(SSH_LOG_WARN, "dup2: %s", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (devnull > STDERR_FILENO) {
|
||||
close(devnull);
|
||||
}
|
||||
|
||||
argv[0] = shell;
|
||||
argv[1] = (char *) "-c";
|
||||
argv[2] = strdup(cmd);
|
||||
argv[3] = NULL;
|
||||
|
||||
rc = execv(argv[0], argv);
|
||||
if (rc == -1) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Failed to execute command '%s': %s", cmd,
|
||||
strerror(errno));
|
||||
/* Die with signal to make this error apparent to parent. */
|
||||
signal(SIGTERM, SIG_DFL);
|
||||
kill(getpid(), SIGTERM);
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Parent */
|
||||
close(devnull);
|
||||
if (pid == -1) { /* Error */
|
||||
SSH_LOG(SSH_LOG_WARN, "Failed to fork child: %s", strerror(errno));
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
while (waitpid(pid, &status, 0) == -1) {
|
||||
if (errno != EINTR) {
|
||||
SSH_LOG(SSH_LOG_WARN, "waitpid failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (!WIFEXITED(status)) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Command %s exitted abnormally", cmd);
|
||||
return -1;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_TRACE, "Command '%s' returned %d", cmd, WEXITSTATUS(status));
|
||||
return WEXITSTATUS(status);
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_match_exec(ssh_session session, const char *command, bool negate)
|
||||
{
|
||||
int rv, result = 0;
|
||||
char *cmd = NULL;
|
||||
|
||||
/* TODO There should be more supported expansions */
|
||||
cmd = ssh_path_expand_escape(session, command);
|
||||
rv = ssh_exec_shell(cmd);
|
||||
if (rv > 0 && negate == true) {
|
||||
result = 1;
|
||||
} else if (rv == 0 && negate == false) {
|
||||
result = 1;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_TRACE, "%s 'exec' command '%s'%s (rv=%d)",
|
||||
result == 1 ? "Matched" : "Not matched", cmd,
|
||||
negate == true ? " (negated)" : "", rv);
|
||||
free(cmd);
|
||||
return result;
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/* @brief: Parse the ProxyJump configuration line and if parsing,
|
||||
* stores the result in the configuration option
|
||||
*/
|
||||
@ -497,20 +624,22 @@ ssh_config_parse_line(ssh_session session,
|
||||
break;
|
||||
|
||||
case MATCH_EXEC:
|
||||
/* Skip to the end of line as unsupported */
|
||||
p = ssh_config_get_cmd(&s);
|
||||
/* Skip one argument (including in quotes) */
|
||||
p = ssh_config_get_token(&s);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword "
|
||||
"'%s' requires argument", count, p2);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
if (result != 1) {
|
||||
SSH_LOG(SSH_LOG_INFO, "line %d: Skipped match exec "
|
||||
"'%s' as previous conditions already failed.",
|
||||
count, p2);
|
||||
continue;
|
||||
}
|
||||
result &= ssh_match_exec(session, p, negate);
|
||||
args++;
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Unsupported Match keyword '%s', ignoring",
|
||||
count,
|
||||
p2);
|
||||
result = 0;
|
||||
break;
|
||||
|
||||
case MATCH_LOCALUSER:
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user