"Failed to disconnect from controlling tty."

This is a part of ssh-1.2.33 ported to QNX v4 by J.C.Michot.
If a remote user requests tty allocation - sshd logs
Failed to disconnect from controlling tty.” but works…

Debugging shows that the only thing that happens here not
the same way as in unixes is the ctname - it is “//2/dev/ttyp0”, not just plain “/dev/tty”.
opening it, ioctling and closeing it and reopening it goes OK. I can see that it’s fd is of value 3 before and after the check.

/* 
  
pty.c 
  
Author: Tatu Ylonen <ylo@ssh.fi> 
  
Copyright (c) 1995 Tatu Ylonen <ylo@ssh.fi>, Espoo, Finland 
Copyright (c) 1995-1999 SSH Communications Security Oy, 
Espoo, Finland 
                        All rights reserved 
  
Created: Fri Mar 17 04:37:25 1995 ylo 
  
Allocating a pseudo-terminal, and making it the controlling 
tty. 
  
*/ 
  
...snip... 
  
/* Makes the tty the processes controlling tty and sets it 
to sane modes. */ 
  
void pty_make_controlling_tty(int *ttyfd, const char 
*ttyname) 
{ 
  int fd; 
#ifdef __QNX__ 
  int cterr = 0; 
#endif 
  char *ctname = "/dev/tty"; 
  
#ifdef __QNX__ 
  if (!(ctname = ctermid(NULL)) || *ctname == '\0') 
    error("Failed to find the controlling tty."); 
  else 
  { 
#endif 
  /* First disconnect from the old controlling tty. */ 
#ifdef TIOCNOTTY 
  fd = open(ctname, O_RDWR|O_NOCTTY); 
  if (fd >= 0) 
    { 
      (void)ioctl(fd, TIOCNOTTY, NULL); 
      close(fd); 
    } 
#endif /* TIOCNOTTY */ 
  
  /* Verify that we are successfully disconnected from the 
controlling tty. */ 
  fd = open(ctname, O_RDWR|O_NOCTTY); 
  if (fd >= 0) 
    { 
      error("Failed to disconnect from controlling tty."); 
      close(fd); 
    } 
#ifdef __QNX__ 
  } 
#endif 
  
  /* Make it our controlling tty. */ 
#ifdef __QNX__ 
  debug("Setting controlling tty using tcsetct()."); 
  if ((cterr = tcsetct(*ttyfd, getpid())) == -1) 
    error("tcsetct() on %.100s failed: %.100s", ttyname, 
strerror(errno)); 
#else 
#ifdef TIOCSCTTY 
  debug("Setting controlling tty using TIOCSCTTY."); 
  /* We ignore errors from this, because HPSUX defines 
TIOCSCTTY, but returns 
     EINVAL with these arguments, and there is absolutely 
no documentation. */ 
  ioctl(*ttyfd, TIOCSCTTY, NULL); 
#endif /* TIOCSCTTY */ 
#endif /* __QNX__ */ 
  
#ifdef __QNX__ 
  fcntl(*ttyfd, F_SETFD, FD_CLOEXEC); 
#endif 
  
...snip... 
  
#ifdef HAVE_SETPGID 
  /* This appears to be necessary on some machines...  */ 
  setpgid(0, 0); 
#endif 
  
  fd = open(ttyname, O_RDWR); 
  if (fd < 0) 
    error("open %.100s failed: %.100s", ttyname, 
strerror(errno)); 
#ifndef __QNX__ 
  else 
    close(fd); 
#endif 
  
#ifdef __QNX__ 
  if (cterr == -1) 
  { 
    if (fd >= 0) close(fd); 
    close(*ttyfd); 
    *ttyfd = -1; 
  } 
  else 
  { 
    close(*ttyfd); 
    *ttyfd = fd; 
  } 
#else 
  /* Verify that we now have a controlling tty. */ 
  fd = open(ctname, O_WRONLY); 
  if (fd < 0) 
    error("open %s failed; could not set controlling tty: 
 %.100s", 
          ctname, strerror(errno)); 
  else 
    { 
      close(fd); 
#if defined(HAVE_VHANGUP) && !defined(HAVE_REVOKE) 
      signal(SIGHUP, SIG_IGN); 
      vhangup(); 
      signal(SIGHUP, SIG_DFL); 
      fd = open(ttyname, O_RDWR); 
      if (fd == -1) 
        error("pty_make_controlling_tty: reopening 
controlling tty after vhangup failed for %.100s", 
              ttyname); 
      close(*ttyfd); 
      *ttyfd = fd; 
#endif /* HAVE_VHANGUP && !HAVE_REVOKE */ 
    } 
#endif /* __QNX__ */ 
} 
...snip... 

What is the correct way of doing this in QNX v4?

Tony.

This is a snip from the code of SSH2 v3.2.9.1:

[code]/*
pty-bsd.c

Author: Tatu Ylonen ylo@ssh.fi

Copyright (c) 1997 SSH Communications Security, Finland
All rights reserved

Allocating a pty on a generic BSD-like system.
*/

/* Makes the given tty the controlling tty of the current process.
This may close and reopen the original file descriptor. When called,
*ttyfd should be a valid file descriptor for the slave side, and ttyname
should contain its name (e.g., “/dev/ttyp3”). Returns FALSE if the
controlling tty could not be set. */

Boolean ssh_pty_internal_make_ctty(int *ttyfd, const char *ttyname)
{
int fd;

/* First disconnect from the old controlling tty. */
fd = open("/dev/tty", O_RDWR|O_NOCTTY);
if (fd >= 0) {
(void)ioctl(fd, TIOCNOTTY, NULL);
close(fd);
}

/* Verify that we are successfully disconnected from the controlling tty. */
fd = open("/dev/tty", O_RDWR|O_NOCTTY);
if (fd >= 0) {
ssh_warning(“Failed to disconnect from controlling tty.”);
close(fd);
}

/* Make it our controlling tty. */
ssh_debug(“Setting controlling tty using TIOCSCTTY.”);
ioctl(*ttyfd, TIOCSCTTY, NULL);

if ( setsid() == -1 ) ssh_warning(“setsid() failed.”);

}[/code]

When running it under QNX v4.25G I get both warnings - “Failed to disconnect…” and “setsid() failed.”. What’s wrong with this code?
Reading the archives on inn.qnx.com I saw postings regarding troubles with “controlling tty”, but there was no hint if it was solved.

Tony.

PS Actually SSH2 works, I just don’t like it littering syslog with theese warnings…

For QNX, since you are using JC’s hack, there is no need to disconnect the old controlling tty. This explains why your ssh still works fine even with those errors. If you really worry about the error, you can just #ifdef out the code:

  /* First disconnect from the old controlling tty. */ 
  fd = open("/dev/tty", O_RDWR|O_NOCTTY); 
  if (fd >= 0) { 
      (void)ioctl(fd, TIOCNOTTY, NULL); 
      close(fd); 
  } 
  
  /* Verify that we are successfully disconnected from the controlling tty. */ 
  fd = open("/dev/tty", O_RDWR|O_NOCTTY); 
  if (fd >= 0) { 
      ssh_warning("Failed to disconnect from controlling tty."); 
      close(fd); 
  } 

Same applies to the setsid() and setpgid(0,0).

Hm-m?..
What J.C. hack? This part of the code is unpatched. (setsid’s warning was added by me to see if it really works, I’ll remove it.)

I wonder what is different between QNX and other *NIXes regarding the controlling tty. Why “faulty” code works still under QNX?

Tony.

I think you didn’t get my point.
OK, here is I would patch the “lib/sshsession/sshunixptystream.c” file:

--- sshunixptystream.c.orig     Wed Dec  3 05:17:20 2003
+++ sshunixptystream.c  Wed Jun  9 22:07:41 2004
@@ -111,8 +111,13 @@
 #include "sshtimeouts.h"
 #include "sigchld.h"
 
-#define SSH_DEBUG_MODULE "SshUnixPtyStream"
+#if defined(__QNX__)
+int qsetlogin( char *login, char *ttyname );
+#endif
 
+
+#define SSH_DEBUG_MODULE "SshUnixPtyStream"
+
 typedef enum {
   SSH_PTY_NORMAL,
   SSH_PTY_BSD_PACKET
@@ -343,8 +348,14 @@
 #endif /* ultrix */
 #endif /* HAVE_SETSID */
 
+#if defined(__QNX__)
+        qsetlogin( getpwuid(owner_uid)->pw_name, namebuf );
+        ioctl(ttyfd, TIOCSCTTY, NULL);
+#else
+
       /* Set controlling tty. */
       ssh_pty_internal_make_ctty(&ttyfd, namebuf);
+#endif
 
       /* Redirect stdin from the pseudo tty. */
       if (dup2(ttyfd, fileno(stdin)) < 0)
@@ -646,3 +657,42 @@
   ssh_pty_stream_set_callback,
   ssh_pty_stream_destroy
 };
+
+#if defined(__QNX__) && !defined(__QNXNTO__)
+#include <sys/types.h>
+#include <sys/proc_msg.h>
+#include <sys/kernel.h> 
+#include <string.h>
+#include <errno.h>
+        
+struct _proc_session ps;
+struct _proc_session_reply rps;
+        
+int qsetlogin( char *login, char *ttyname )
+{       
+        int v = getsid( getpid() );
+
+        memset( &ps, 0, sizeof(ps) );
+        memset( &rps, 0, sizeof(rps) );
+
+        ps.type = _PROC_SESSION;
+        ps.subtype = _PROC_SUB_ACTION1;
+        ps.sid = v;
+        strcpy( ps.name, login );
+
+        Send( 1, &ps, &rps, sizeof(ps), sizeof(rps) );
+
+        if ( rps.status < 0 )
+                return( rps.status );
+
+        ps.type = _PROC_SESSION;
+        ps.subtype = _PROC_SUB_ACTION2;
+        ps.sid = v;
+        /* sprintf( ps.name, "//%d%s", getnid(), ttyname ); */
+        ssh_snprintf( ps.name, 17, "//%d%s", getnid(), ttyname );
+        Send( 1, &ps, &rps, sizeof(ps), sizeof(rps) );
+
+        return( rps.status );
+}
+#endif
+

The “qsetlogin()” in the above patch is what I meant by JC’s hack because JC came up with that idea first.

As you can see from the above patch, the “ssh_pty_internal_make_ctty” (which is defined in the pty-bsd.c as you posted) won’t even get called because we are now using qsetlogin (JC’s hack) for dealing with the controlling tty. This patch should get rid of those bug errors in the syslog.

This puzzles me even more - how can an already commented-out code issue any warnings?

Well, looks like your sshunixptystream.c didn’t have it commented out?

The below code is the key. Double check your sshunixptystream.c

...
+#if defined(__QNX__) 
+        qsetlogin( getpwuid(owner_uid)->pw_name, namebuf ); 
+        ioctl(ttyfd, TIOCSCTTY, NULL); 
+#else 
+ 
       /* Set controlling tty. */ 
       ssh_pty_internal_make_ctty(&ttyfd, namebuf); 
+#endif 
...

:slight_smile:
That’s better!