[PATCH proposal] FISH: don't let ssh write its ouput to the controlling tty



This patch addresses the problem with ssh writing to the controlling
terminal when asking for password and when displaying a message that the
remote system is not known.

The idea is simple - instead of creating pipes to talk to the ssh/rsh
program create a pseudo terminal and attach ssh to the slave end. This way
ssh outputs to the pty and doesnt break the appearence of MC.

I've tested the patch on Cygwin but it should work on Linux too. I'm not
lazy but I cannot get MC to compile on my RH 8 because it has a dependency
on gettext-0.11.5 which doesnt come with RH 8 :(

I want to know what you think about the changes I've made. I want to
know if you see any potential problems with the replacement of the pipes
with pty.  The patch is not release quality but works (i mean some of the
code should be rearranged a bit). I'll modify it as advised if you think
that it is good for inclusion in the CVS tree.



Index: vfs/fish.c
===================================================================
RCS file: /cvs/gnome/mc/vfs/fish.c,v
retrieving revision 1.58
diff -u -p -r1.58 fish.c
--- vfs/fish.c	13 Nov 2002 04:00:28 -0000	1.58
+++ vfs/fish.c	20 Nov 2002 19:06:07 -0000
@@ -35,6 +35,7 @@
 /* Define this if your ssh can take -I option */
 
 #include <config.h>
+#include <termios.h>
 
 #undef HAVE_HACKED_SSH
 
@@ -46,6 +47,9 @@
 #include "tcputil.h"
 #include "fish.h"
 
+extern int pty_open_master (char *pty_name);
+extern int pty_open_slave (const char *pty_name);
+
 /*
  * Reply codes.
  */
@@ -153,36 +157,6 @@ free_archive (vfs *me, vfs_s_super *supe
     g_free (SUP.password);
 }
 
-static void
-pipeopen(vfs_s_super *super, char *path, char *argv[])
-{
-    int fileset1[2], fileset2[2];
-    int res;
-
-    if ((pipe(fileset1)<0) || (pipe(fileset2)<0)) 
-	vfs_die("Could not pipe(): %m.");
-    
-    if ((res = fork())) {
-        if (res<0) vfs_die("Could not fork(): %m.");
-	/* We are the parent */
-	close(fileset1[0]);
-	SUP.sockw = fileset1[1];
-	close(fileset2[1]);
-	SUP.sockr = fileset2[0];
-    } else {
-        close(0);
-	dup(fileset1[0]);
-	close(fileset1[0]); close(fileset1[1]);
-	close(1); close(2);
-	dup(fileset2[1]);
-	/* stderr to /dev/null */
-	open ("/dev/null", O_WRONLY);
-	close(fileset2[0]); close(fileset2[1]);
-	execvp(path, argv);
-	_exit(3);
-    }
-}
-
 /* The returned directory should always contain a trailing slash */
 static char *fish_getcwd(vfs *me, vfs_s_super *super)
 {
@@ -196,11 +170,11 @@ open_archive_int (vfs *me, vfs_s_super *
     char *argv[100];
     char *xsh = (SUP.flags == FISH_FLAG_RSH ? "rsh" : "ssh");
     int i = 0;
+	int ptym;
+    struct termios pty_mode;
+	char pty_name[1024];
 
     argv[i++] = xsh;
-#ifdef HAVE_HACKED_SSH
-    argv[i++] = "-I";
-#endif
     argv[i++] = "-l";
     argv[i++] = SUP.user;
     argv[i++] = SUP.host;
@@ -212,41 +186,120 @@ open_archive_int (vfs *me, vfs_s_super *
 #if 0
     /* Debugging hack */
     if (!MEDATA->logfile)
-	MEDATA->logfile = fopen( "/home/pavel/talk.fish", "w+" ); /* FIXME */
+	MEDATA->logfile = fopen( "/home/paveltz/talk.fish", "w+" ); /* FIXME */
 #endif
 
-    pipeopen(super, xsh, argv );
+    ptym = pty_open_master (pty_name);
+    tcgetattr (ptym, &pty_mode);
+    pty_mode.c_iflag &= ~ICRNL;
+    pty_mode.c_oflag &= ~OPOST;
+	pty_mode.c_lflag &= ~ICANON;
+    pty_mode.c_lflag &= ~ECHO;
+    tcsetattr (ptym, TCSANOW, &pty_mode);
+    switch (fork ())
+      {
+        case -1:
+          vfs_die("Could not fork(): %m.");
+        case 0:
+          {
+            int ptys;
+            setsid ();
+            ptys = pty_open_slave (pty_name);
+            dup2 (ptys, STDIN_FILENO);
+            dup2 (ptys, STDOUT_FILENO);
+            dup2 (open ("/dev/null", O_WRONLY), STDERR_FILENO);
+            close (ptys);
+            execvp (xsh, argv);
+            _exit(3);
+          }
+        default:
+          {
+            SUP.sockw = SUP.sockr = ptym;
+          }
+      }
+
+    print_vfs_message( _("fish: Waiting for initial line...") );
 
     {
-        char answer[2048];
-	print_vfs_message( _("fish: Waiting for initial line...") );
+    int pass_ok = 0, pass_sent = 0;
+    char c;
+    char answer[240];
+    do
+      {
         if (!vfs_s_get_line(me, SUP.sockr, answer, sizeof(answer), ':'))
-	    ERRNOR (E_PROTO, -1);
-	print_vfs_message( answer );
-	if (strstr(answer, "assword")) {
-
-    /* Currently, this does not work. ssh reads passwords from
-       /dev/tty, not from stdin :-(. */
-
-#ifndef HAVE_HACKED_SSH
-	    message_1s (1, MSG_ERROR, _("Sorry, we can not do password authenticated connections for now."));
-	    ERRNOR (EPERM, -1);
-#endif
-	    if (!SUP.password){
-		char *p, *op;
-		p = g_strconcat (_(" fish: Password required for "), SUP.user, 
-				  " ", NULL);
-		op = vfs_get_password (p);
-		g_free (p);
-		if (op == NULL)
-		    ERRNOR (EPERM, -1);
-		SUP.password = g_strdup (op);
-		wipe_password(op);
-	    }
-	    print_vfs_message( _("fish: Sending password...") );
-	    write(SUP.sockw, SUP.password, strlen(SUP.password));
-	    write(SUP.sockw, "\n", 1);
-	}
+          {
+            if (SUP.password != NULL)
+              {
+                wipe_password (SUP.password);
+                SUP.password = NULL;
+              }
+	        ERRNOR (E_PROTO, -1);
+          }
+	    if (strstr(answer, "assword"))
+          {
+            if (pass_sent != 0)
+              {
+                wipe_password (SUP.password);
+                SUP.password = NULL;
+              }
+	        if (!SUP.password)
+              {
+		        char *p, *op;
+		        p = g_strconcat (_(" fish: Password required for "), SUP.user, 
+				                 " ", NULL);
+		        op = vfs_get_password (p);
+                g_free (p);
+                if (op == NULL)
+                  ERRNOR (EPERM, -1);
+                SUP.password = g_strdup (op);
+                wipe_password(op);
+              }
+            print_vfs_message( _("fish: Sending password...") );
+            write(SUP.sockw, SUP.password, strlen(SUP.password));
+            write(SUP.sockw, "\n", 1);
+            pass_sent = 1;
+          }
+        else if (pass_sent != 0)
+          {
+            if (strstr (answer, "FISH"))
+              {
+                wipe_password (SUP.password);
+                SUP.password = NULL;
+                pass_ok = 1;
+              }
+            /*else if (strstr (answer, "Permission denied"))
+              {
+                wipe_password (SUP.password);
+                g_free (SUP.password);
+                SUP.password = NULL;
+              }*/
+          }
+        else if (strstr (answer, "The authenticity of host"))
+          {
+             /* The identity of the host is not know yet */
+             int yesno;
+             char *msg, *tmp_answer;
+
+             tmp_answer = g_strdup (answer);
+             if (!vfs_s_get_line (me, SUP.sockr, answer,
+                                  sizeof (answer), '?'))
+               {
+                 g_free (tmp_answer);
+                 ERRNOR (EPROTO, -1);
+               }
+             msg = g_strconcat (tmp_answer, ":", answer, "?", NULL);
+
+             yesno = query_dialog (_(" Confirmation "), msg, 0, 2,
+                                   _("&Yes"), _("&No"));
+             g_free (tmp_answer);
+             g_free (msg);
+             if (yesno != 0)
+               return -1;
+             write (SUP.sockw, "yes\n", 4);
+          }
+          /* Discard remaining data */
+          vfs_s_get_line (me, SUP.sockr, &c, 1, '\n');
+      } while (pass_ok == 0);
     }
 
     print_vfs_message( _("fish: Sending initial line...") );

Index: src/subshell.c
===================================================================
RCS file: /cvs/gnome/mc/src/subshell.c,v
retrieving revision 1.57
diff -u -p -r1.57 subshell.c
--- src/subshell.c	14 Nov 2002 17:08:56 -0000	1.57
+++ src/subshell.c	20 Nov 2002 19:13:52 -0000
@@ -73,8 +73,8 @@ static char tcsh_fifo[128];
 static void init_raw_mode (void);
 static int feed_subshell (int how, int fail_on_error);
 static void synchronize (void);
-static int pty_open_master (char *pty_name);
-static int pty_open_slave (const char *pty_name);
+extern int pty_open_master (char *pty_name);
+extern int pty_open_slave (const char *pty_name);
 static int resize_tty (int fd);
 
 /* }}} */
@@ -1092,203 +1092,6 @@ static void synchronize (void)
 
 /* }}} */
 /* {{{ pty opening functions */
-
-#ifdef SCO_FLAVOR
-
-/* {{{ SCO version of pty_open_master */
-
-static int pty_open_master (char *pty_name)
-{
-    int pty_master;
-    int num;
-    char *ptr;
-
-    strcpy (pty_name, "/dev/ptyp");
-    ptr = pty_name+9;
-    for (num=0;;num++)
-    {
-	g_snprintf(ptr, 9, "%d",num);	/* surpriiise ... SCO lacks itoa() */
-	/* Try to open master */
-	if ((pty_master = open (pty_name, O_RDWR)) == -1) {
-	    if (errno == ENOENT)  /* Different from EIO */
-		return -1;	      /* Out of pty devices */
-	    else
-		continue;	      /* Try next pty device */
-	}
-	pty_name [5] = 't';	      /* Change "pty" to "tty" */
-	if (access (pty_name, 6)){
-	    close (pty_master);
-	    pty_name [5] = 'p';
-	    continue;
-	}
-	return pty_master;
-    }
-    return -1;  /* Ran out of pty devices */
-}
-
-/* }}} */
-/* {{{ SCO version of pty_open_slave */
-
-static int pty_open_slave (const char *pty_name)
-{
-    int pty_slave;
-    struct group *group_info = getgrnam ("terminal");
-    
-    if (group_info != NULL)
-    {
-	/* The following two calls will only succeed if we are root */
-	/* [Commented out while permissions problem is investigated] */
-	/* chown (pty_name, getuid (), group_info->gr_gid);  FIXME */
-	/* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP);   FIXME */
-    }
-    if ((pty_slave = open (pty_name, O_RDWR)) == -1)
-	perror ("open (pty_name, O_RDWR)");
-    return pty_slave;
-}
-
-/* }}} */
-
-#elif HAVE_GRANTPT /* !HAVE_SCO */
-
-/* {{{ System V version of pty_open_master */
-
-static int pty_open_master (char *pty_name)
-{
-    char *slave_name;
-    int pty_master;
-
-
-#ifdef HAVE_GETPT
-    /* getpt () is a GNU extension (glibc 2.1.x) */
-    pty_master = getpt ();
-#elif IS_AIX
-    strcpy (pty_name, "/dev/ptc");
-    pty_master = open (pty_name, O_RDWR);
-#else
-    strcpy (pty_name, "/dev/ptmx");
-    pty_master = open (pty_name, O_RDWR);
-#endif 
-    if (pty_master == -1)
-	return -1;
-
-    if (grantpt (pty_master) == -1		  /* Grant access to slave */
-	|| unlockpt (pty_master) == -1		  /* Clear slave's lock flag */
-	|| !(slave_name = ptsname (pty_master)))  /* Get slave's name */
-    {
-	close (pty_master);
-	return -1;
-    }
-    strcpy (pty_name, slave_name);
-    return pty_master;
-}
-
-/* }}} */
-/* {{{ System V version of pty_open_slave */
-
-static int pty_open_slave (const char *pty_name)
-{
-    int pty_slave = open (pty_name, O_RDWR);
-
-    if (pty_slave == -1)
-    {
-	perror ("open (pty_name, O_RDWR)");
-	return -1;
-    }
-
-#if !defined(__osf__) && !defined(linux) && !defined(__linux__)
-#if defined (I_FIND) && defined (I_PUSH)
-    if (!ioctl (pty_slave, I_FIND, "ptem"))
-	if (ioctl (pty_slave, I_PUSH, "ptem") == -1)
-	{
-	    fprintf (stderr, "ioctl (pty_slave, I_PUSH, \"ptem\") failed\n");
-	    close (pty_slave);
-	    return -1;
-	}
-	
-    if (!ioctl (pty_slave, I_FIND, "ldterm"))
-        if (ioctl (pty_slave, I_PUSH, "ldterm") == -1)
-	{
-	    fprintf (stderr, "ioctl (pty_slave, I_PUSH, \"ldterm\") failed\n");
-	    close (pty_slave);
-	    return -1;
-	}
-
-#if !defined(sgi) && !defined(__sgi)
-    if (!ioctl (pty_slave, I_FIND, "ttcompat"))
-        if (ioctl (pty_slave, I_PUSH, "ttcompat") == -1)
-	{
-	    fprintf (stderr, "ioctl (pty_slave, I_PUSH, \"ttcompat\") failed\n");
-	    close (pty_slave);
-	    return -1;
-	}
-#endif /* sgi || __sgi */
-#endif /* I_FIND && I_PUSH */
-#endif /* __osf__ || linux || __linux__ */
-
-    return pty_slave;
-}
-
-/* }}} */
-
-#else /* !HAVE_SCO && !HAVE_GRANTPT */
-
-/* {{{ BSD version of pty_open_master */
-
-static int pty_open_master (char *pty_name)
-{
-    int pty_master;
-    char *ptr1, *ptr2;
-
-    strcpy (pty_name, "/dev/ptyXX");
-    for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1; ++ptr1)
-    {
-	pty_name [8] = *ptr1;
-	for (ptr2 = "0123456789abcdef"; *ptr2; ++ptr2)
-	{
-	    pty_name [9] = *ptr2;
-
-	    /* Try to open master */
-	    if ((pty_master = open (pty_name, O_RDWR)) == -1) {
-		if (errno == ENOENT)  /* Different from EIO */
-		    return -1;	      /* Out of pty devices */
-		else
-		    continue;	      /* Try next pty device */
-	    }
-	    pty_name [5] = 't';	      /* Change "pty" to "tty" */
-	    if (access (pty_name, 6)){
-		close (pty_master);
-		pty_name [5] = 'p';
-		continue;
-	    }
-	    return pty_master;
-	}
-    }
-    return -1;  /* Ran out of pty devices */
-}
-
-/* }}} */
-/* {{{ BSD version of pty_open_slave */
-
-static int pty_open_slave (const char *pty_name)
-{
-    int pty_slave;
-    struct group *group_info = getgrnam ("tty");
-
-    if (group_info != NULL)
-    {
-	/* The following two calls will only succeed if we are root */
-	/* [Commented out while permissions problem is investigated] */
-	/* chown (pty_name, getuid (), group_info->gr_gid);  FIXME */
-	/* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP);   FIXME */
-    }
-    if ((pty_slave = open (pty_name, O_RDWR)) == -1)
-	perror ("open (pty_name, O_RDWR)");
-    return pty_slave;
-}
-
-/* }}} */
-
-#endif /* !HAVE_SCO && !HAVE_GRANTPT */
 
 /* }}} */
 
Index: src/utilunix.c
===================================================================
RCS file: /cvs/gnome/mc/src/utilunix.c,v
retrieving revision 1.52
diff -u -p -r1.52 utilunix.c
--- src/utilunix.c	14 Nov 2002 07:25:19 -0000	1.52
+++ src/utilunix.c	20 Nov 2002 19:13:53 -0000
@@ -839,3 +839,200 @@ int socketpair(int dummy1, int dummy2, i
 #endif /* ifndef HAVE_SOCKETPAIR */
 #endif /* ifdef USE_NETCODE */
 #endif /* SCO_FLAVOR */
+
+#ifdef SCO_FLAVOR
+
+/* {{{ SCO version of pty_open_master */
+
+int pty_open_master (char *pty_name)
+{
+    int pty_master;
+    int num;
+    char *ptr;
+
+    strcpy (pty_name, "/dev/ptyp");
+    ptr = pty_name+9;
+    for (num=0;;num++)
+    {
+	g_snprintf(ptr, 9, "%d",num);	/* surpriiise ... SCO lacks itoa() */
+	/* Try to open master */
+	if ((pty_master = open (pty_name, O_RDWR)) == -1) {
+	    if (errno == ENOENT)  /* Different from EIO */
+		return -1;	      /* Out of pty devices */
+	    else
+		continue;	      /* Try next pty device */
+	}
+	pty_name [5] = 't';	      /* Change "pty" to "tty" */
+	if (access (pty_name, 6)){
+	    close (pty_master);
+	    pty_name [5] = 'p';
+	    continue;
+	}
+	return pty_master;
+    }
+    return -1;  /* Ran out of pty devices */
+}
+
+/* }}} */
+/* {{{ SCO version of pty_open_slave */
+
+int pty_open_slave (const char *pty_name)
+{
+    int pty_slave;
+    struct group *group_info = getgrnam ("terminal");
+    
+    if (group_info != NULL)
+    {
+	/* The following two calls will only succeed if we are root */
+	/* [Commented out while permissions problem is investigated] */
+	/* chown (pty_name, getuid (), group_info->gr_gid);  FIXME */
+	/* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP);   FIXME */
+    }
+    if ((pty_slave = open (pty_name, O_RDWR)) == -1)
+	perror ("open (pty_name, O_RDWR)");
+    return pty_slave;
+}
+
+/* }}} */
+
+#elif HAVE_GRANTPT /* !HAVE_SCO */
+
+/* {{{ System V version of pty_open_master */
+
+int pty_open_master (char *pty_name)
+{
+    char *slave_name;
+    int pty_master;
+
+
+#ifdef HAVE_GETPT
+    /* getpt () is a GNU extension (glibc 2.1.x) */
+    pty_master = getpt ();
+#elif IS_AIX
+    strcpy (pty_name, "/dev/ptc");
+    pty_master = open (pty_name, O_RDWR);
+#else
+    strcpy (pty_name, "/dev/ptmx");
+    pty_master = open (pty_name, O_RDWR);
+#endif 
+    if (pty_master == -1)
+	return -1;
+
+    if (grantpt (pty_master) == -1		  /* Grant access to slave */
+	|| unlockpt (pty_master) == -1		  /* Clear slave's lock flag */
+	|| !(slave_name = ptsname (pty_master)))  /* Get slave's name */
+    {
+	close (pty_master);
+	return -1;
+    }
+    strcpy (pty_name, slave_name);
+    return pty_master;
+}
+
+/* }}} */
+/* {{{ System V version of pty_open_slave */
+
+int pty_open_slave (const char *pty_name)
+{
+    int pty_slave = open (pty_name, O_RDWR);
+
+    if (pty_slave == -1)
+    {
+	perror ("open (pty_name, O_RDWR)");
+	return -1;
+    }
+
+#if !defined(__osf__) && !defined(linux) && !defined(__linux__)
+#if defined (I_FIND) && defined (I_PUSH)
+    if (!ioctl (pty_slave, I_FIND, "ptem"))
+	if (ioctl (pty_slave, I_PUSH, "ptem") == -1)
+	{
+	    fprintf (stderr, "ioctl (pty_slave, I_PUSH, \"ptem\") failed\n");
+	    close (pty_slave);
+	    return -1;
+	}
+	
+    if (!ioctl (pty_slave, I_FIND, "ldterm"))
+        if (ioctl (pty_slave, I_PUSH, "ldterm") == -1)
+	{
+	    fprintf (stderr, "ioctl (pty_slave, I_PUSH, \"ldterm\") failed\n");
+	    close (pty_slave);
+	    return -1;
+	}
+
+#if !defined(sgi) && !defined(__sgi)
+    if (!ioctl (pty_slave, I_FIND, "ttcompat"))
+        if (ioctl (pty_slave, I_PUSH, "ttcompat") == -1)
+	{
+	    fprintf (stderr, "ioctl (pty_slave, I_PUSH, \"ttcompat\") failed\n");
+	    close (pty_slave);
+	    return -1;
+	}
+#endif /* sgi || __sgi */
+#endif /* I_FIND && I_PUSH */
+#endif /* __osf__ || linux || __linux__ */
+
+    return pty_slave;
+}
+
+/* }}} */
+
+#else /* !HAVE_SCO && !HAVE_GRANTPT */
+
+/* {{{ BSD version of pty_open_master */
+
+int pty_open_master (char *pty_name)
+{
+    int pty_master;
+    char *ptr1, *ptr2;
+
+    strcpy (pty_name, "/dev/ptyXX");
+    for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1; ++ptr1)
+    {
+	pty_name [8] = *ptr1;
+	for (ptr2 = "0123456789abcdef"; *ptr2; ++ptr2)
+	{
+	    pty_name [9] = *ptr2;
+
+	    /* Try to open master */
+	    if ((pty_master = open (pty_name, O_RDWR)) == -1) {
+		if (errno == ENOENT)  /* Different from EIO */
+		    return -1;	      /* Out of pty devices */
+		else
+		    continue;	      /* Try next pty device */
+	    }
+	    pty_name [5] = 't';	      /* Change "pty" to "tty" */
+	    if (access (pty_name, 6)){
+		close (pty_master);
+		pty_name [5] = 'p';
+		continue;
+	    }
+	    return pty_master;
+	}
+    }
+    return -1;  /* Ran out of pty devices */
+}
+
+/* }}} */
+/* {{{ BSD version of pty_open_slave */
+
+int pty_open_slave (const char *pty_name)
+{
+    int pty_slave;
+    struct group *group_info = getgrnam ("tty");
+
+    if (group_info != NULL)
+    {
+	/* The following two calls will only succeed if we are root */
+	/* [Commented out while permissions problem is investigated] */
+	/* chown (pty_name, getuid (), group_info->gr_gid);  FIXME */
+	/* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP);   FIXME */
+    }
+    if ((pty_slave = open (pty_name, O_RDWR)) == -1)
+	perror ("open (pty_name, O_RDWR)");
+    return pty_slave;
+}
+
+/* }}} */
+
+#endif /* !HAVE_SCO && !HAVE_GRANTPT */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]