Browse Source

Don't create tty for interactive commands if client has no terminal

Serj Kalichev 7 months ago
parent
commit
24c012b551
6 changed files with 85 additions and 12 deletions
  1. 8 0
      klish/ksession.h
  2. 6 0
      klish/ksession/kexec.c
  3. 14 0
      klish/ksession/ksession.c
  4. 6 2
      klish/ktp.h
  5. 41 10
      klish/ktp/ktp_session.c
  6. 10 0
      klish/ktp/ktpd_session.c

+ 8 - 0
klish/ksession.h

@@ -46,6 +46,14 @@ bool_t ksession_set_uid(ksession_t *session, uid_t uid);
 const char *ksession_user(const ksession_t *session);
 bool_t ksession_set_user(ksession_t *session, const char *user);
 
+// Client isatty
+bool_t ksession_isatty_stdin(const ksession_t *session);
+bool_t ksession_set_isatty_stdin(ksession_t *session, bool_t isatty_stdin);
+bool_t ksession_isatty_stdout(const ksession_t *session);
+bool_t ksession_set_isatty_stdout(ksession_t *session, bool_t isatty_stdout);
+bool_t ksession_isatty_stderr(const ksession_t *session);
+bool_t ksession_set_isatty_stderr(ksession_t *session, bool_t isatty_stderr);
+
 C_DECL_END
 
 #endif // _klish_ksession_h

+ 6 - 0
klish/ksession/kexec.c

@@ -329,6 +329,7 @@ static bool_t kexec_prepare(kexec_t *exec)
 		return BOOL_TRUE;
 	}
 
+	// Commands without pseudoterminal
 	// Create "global" stdin, stdout, stderr for the whole job execution.
 
 	// STDIN
@@ -747,6 +748,7 @@ bool_t kexec_interactive(const kexec_t *exec)
 	faux_list_node_t *node = NULL;
 	kcontext_t *context = NULL;
 	const kentry_t *entry = NULL;
+	const ksession_t *session = NULL;
 
 	assert(exec);
 	if (!exec)
@@ -759,6 +761,10 @@ bool_t kexec_interactive(const kexec_t *exec)
 	context = (kcontext_t *)faux_list_data(node);
 	if (!context)
 		return BOOL_FALSE;
+	// If client has no input tty then consider command as non-interactive
+	session = kcontext_session(context);
+	if (session && !ksession_isatty_stdin(session))
+		return BOOL_FALSE;
 	entry = kcontext_command(context);
 	if (!entry)
 		return BOOL_FALSE;

+ 14 - 0
klish/ksession/ksession.c

@@ -21,6 +21,9 @@ struct ksession_s {
 	pid_t pid;
 	uid_t uid;
 	char *user;
+	bool_t isatty_stdin;
+	bool_t isatty_stdout;
+	bool_t isatty_stderr;
 };
 
 
@@ -54,6 +57,14 @@ KSET(session, uid_t, uid);
 KSET_STR(session, user);
 KGET_STR(session, user);
 
+// isatty
+KGET_BOOL(session, isatty_stdin);
+KSET_BOOL(session, isatty_stdin);
+KGET_BOOL(session, isatty_stdout);
+KSET_BOOL(session, isatty_stdout);
+KGET_BOOL(session, isatty_stderr);
+KSET_BOOL(session, isatty_stderr);
+
 
 ksession_t *ksession_new(kscheme_t *scheme, const char *start_entry)
 {
@@ -100,6 +111,9 @@ ksession_t *ksession_new(kscheme_t *scheme, const char *start_entry)
 	session->pid = -1;
 	session->uid = -1;
 	session->user = NULL;
+	session->isatty_stdin = BOOL_FALSE;
+	session->isatty_stdout = BOOL_FALSE;
+	session->isatty_stderr = BOOL_FALSE;
 
 	return session;
 }

+ 6 - 2
klish/ktp.h

@@ -49,7 +49,9 @@ typedef enum {
 	KTP_STATUS_ERROR =		(uint32_t)0x00000001,
 	KTP_STATUS_INCOMPLETED =	(uint32_t)0x00000002,
 	KTP_STATUS_INTERACTIVE =	(uint32_t)0x00000100,
-	KTP_STATUS_TTY =		(uint32_t)0x00000200,
+	KTP_STATUS_TTY_STDIN =		(uint32_t)0x00000200,
+	KTP_STATUS_TTY_STDOUT =		(uint32_t)0x00000400,
+	KTP_STATUS_TTY_STDERR =		(uint32_t)0x00000800,
 	KTP_STATUS_DRY_RUN =		(uint32_t)0x00010000,
 	KTP_STATUS_EXIT =		(uint32_t)0x80000000,
 } ktp_status_e;
@@ -57,7 +59,9 @@ typedef enum {
 #define KTP_STATUS_IS_ERROR(status) (status & KTP_STATUS_ERROR)
 #define KTP_STATUS_IS_INCOMPLETED(status) (status & KTP_STATUS_INCOMPLETED)
 #define KTP_STATUS_IS_INTERACTIVE(status) (status & KTP_STATUS_INTERACTIVE)
-#define KTP_STATUS_IS_TTY(status) (status & KTP_STATUS_TTY)
+#define KTP_STATUS_IS_TTY_STDIN(status) (status & KTP_STATUS_TTY_STDIN)
+#define KTP_STATUS_IS_TTY_STDOUT(status) (status & KTP_STATUS_TTY_STDOUT)
+#define KTP_STATUS_IS_TTY_STDERR(status) (status & KTP_STATUS_TTY_STDERR)
 #define KTP_STATUS_IS_DRY_RUN(status) (status & KTP_STATUS_DRY_RUN)
 #define KTP_STATUS_IS_EXIT(status) (status & KTP_STATUS_EXIT)
 

+ 41 - 10
klish/ktp/ktp_session.c

@@ -605,6 +605,22 @@ static bool_t ktp_session_read_cb(faux_async_t *async,
 }
 
 
+static bool_t ktp_session_drop_state(ktp_session_t *ktp, faux_error_t *error)
+{
+	assert(ktp);
+	if (!ktp)
+		return BOOL_FALSE;
+
+	ktp->error = error;
+	ktp->cmd_retcode = -1;
+	ktp->cmd_retcode_available = BOOL_FALSE;
+	ktp->request_done = BOOL_FALSE;
+	ktp->cmd_features = KTP_STATUS_NONE;
+	ktp->cmd_features_available = BOOL_FALSE;
+
+	return BOOL_TRUE;
+}
+
 static bool_t ktp_session_req(ktp_session_t *ktp, ktp_cmd_e cmd,
 	const char *line, size_t line_len, faux_error_t *error,
 	bool_t dry_run, bool_t drop_state)
@@ -627,14 +643,8 @@ static bool_t ktp_session_req(ktp_session_t *ktp, ktp_cmd_e cmd,
 	faux_msg_free(req);
 
 	// Prepare for loop
-	if (drop_state) {
-		ktp->error = error;
-		ktp->cmd_retcode = -1;
-		ktp->cmd_retcode_available = BOOL_FALSE;
-		ktp->request_done = BOOL_FALSE;
-		ktp->cmd_features = KTP_STATUS_NONE;
-		ktp->cmd_features_available = BOOL_FALSE;
-	}
+	if (drop_state)
+		ktp_session_drop_state(ktp, error);
 
 	return BOOL_TRUE;
 }
@@ -654,9 +664,30 @@ bool_t ktp_session_cmd(ktp_session_t *ktp, const char *line,
 
 bool_t ktp_session_auth(ktp_session_t *ktp, faux_error_t *error)
 {
-	if (!ktp_session_req(ktp, KTP_AUTH, NULL, 0,
-		error, BOOL_FALSE, BOOL_TRUE))
+	faux_msg_t *req = NULL;
+	ktp_status_e status = KTP_STATUS_NONE;
+
+	assert(ktp);
+	if (!ktp)
 		return BOOL_FALSE;
+
+	// This request starts session. It must send some client's environment
+	// to server
+	if (isatty(STDIN_FILENO))
+		status |= KTP_STATUS_TTY_STDIN;
+	if (isatty(STDOUT_FILENO))
+		status |= KTP_STATUS_TTY_STDOUT;
+	if (isatty(STDERR_FILENO))
+		status |= KTP_STATUS_TTY_STDERR;
+
+	// Send request
+	req = ktp_msg_preform(KTP_AUTH, status);
+	faux_msg_send_async(req, ktp->async);
+	faux_msg_free(req);
+
+	// Prepare for loop
+	ktp_session_drop_state(ktp, error);
+
 	ktp->state = KTP_SESSION_STATE_UNAUTHORIZED;
 
 	return BOOL_TRUE;

+ 10 - 0
klish/ktp/ktpd_session.c

@@ -268,6 +268,7 @@ static bool_t ktpd_session_process_auth(ktpd_session_t *ktpd, faux_msg_t *msg)
 	char *user = NULL;
 	kcontext_t *context = NULL;
 	kscheme_t *scheme = NULL;
+	uint32_t client_status = KTP_STATUS_NONE;
 
 	assert(ktpd);
 	assert(msg);
@@ -290,6 +291,15 @@ static bool_t ktpd_session_process_auth(ktpd_session_t *ktpd, faux_msg_t *msg)
 	ksession_set_user(ktpd->session, user);
 	faux_str_free(user);
 
+	// Get tty information from auth message status
+	client_status = faux_msg_get_status(msg);
+	ksession_set_isatty_stdin(ktpd->session,
+		KTP_STATUS_IS_TTY_STDIN(client_status));
+	ksession_set_isatty_stdout(ktpd->session,
+		KTP_STATUS_IS_TTY_STDOUT(client_status));
+	ksession_set_isatty_stderr(ktpd->session,
+		KTP_STATUS_IS_TTY_STDERR(client_status));
+
 	// init session for plugins
 	scheme = ksession_scheme(ktpd->session);
 	context = kcontext_new(KCONTEXT_TYPE_PLUGIN_INIT);