Re: Transferring ownership of SSH connection from process A to B, letting A quit nicely?

2021-08-11 Thread mid
On Wednesday, August 11th, 2021 at 7:57 AM, m brandenberg  
wrote:

> Check msg.msg_flags here. I think you will receive a hint.

msg_flags is always zero. Seems okay, after all, the FDs are received correctly.



Re: Transferring ownership of SSH connection from process A to B, letting A quit nicely?

2021-08-11 Thread Philip Guenther
On Tue, Aug 10, 2021 at 12:13 PM mid  wrote:

> On Monday, August 9th, 2021 at 5:36 AM, Philip Guenther <
> guent...@gmail.com> wrote:
>
> > If you're 100% sure you have it right, then it should be easy to provide
> a
> > program that demonstrates
> > 1.  passing an fd between processes
> > 2.  using it successfully in the receiving process
> > 3.  the sending process exiting
> > 4.  attempts to us it failing the receiving process
>
> Not 100%, but I'm out of ideas, so here goes nothing.
>
> client.c (process A):
>
...

> Compiled with:
>   cc -std=c99 -o server server.c
>   cc -std=c99 -o client client.c
>
> `client` is also the shell of the user, but the results are the same if
> I call it from within a "real" shell, too.
>
> The server receives the correct FDs, and prints
> "Hello from the Server\n" correctly, too. But as soon as `client`
> exits, the SSH connection goes with it, instead of staying (as in,
> I get "Connection to localhost closed").
>

Your problems have nothing to do with fd passing but rather are around not
understanding how session management works.
The client is passing its stdin/stdout, which are either pipes or a
pseudo-tty connected to the ssh server and NOT the actual TCP socket
carrying the ssh connection.  When the session leader process exits the
kernel will perform various cleanup operations (block tty access, send some
signals).

If you _really_ want to hack around in this area, you need to do a bunch of
reading and research.  I recommend buying/borrowing a copy of
_Advanced_Programming_in_the_UNIX_Environment_ by W. Richard Stevens.


Philip Guenther


Re: Transferring ownership of SSH connection from process A to B, letting A quit nicely?

2021-08-11 Thread m brandenberg

On Tue, 10 Aug 2021, mid wrote:


 len = recvmsg(socket, &msg, 0);

 if(len <= 0) {
   return -1;
 }


Check msg.msg_flags here.  I think you will receive a hint.

--
Monty Brandenberg



Re: Transferring ownership of SSH connection from process A to B, letting A quit nicely?

2021-08-10 Thread mid
On Monday, August 9th, 2021 at 5:36 AM, Philip Guenther  
wrote:

> If you're 100% sure you have it right, then it should be easy to provide a
> program that demonstrates
> 1.  passing an fd between processes
> 2.  using it successfully in the receiving process
> 3.  the sending process exiting
> 4.  attempts to us it failing the receiving process

Not 100%, but I'm out of ideas, so here goes nothing.

client.c (process A):

#include
#include
#include
#include
#include

int sendfd(int sock, int fd) {
  struct msghdr msg;
  struct iovec iov[1];
  struct cmsghdr *cmsg = NULL;
  char ctrl_buf[CMSG_SPACE(sizeof(int))];
  char data[1];

  memset(&msg, 0, sizeof(struct msghdr));
  memset(ctrl_buf, 0, CMSG_SPACE(sizeof(int)));

  data[0] = ' ';
  iov[0].iov_base = data;
  iov[0].iov_len = sizeof(data);

  msg.msg_name = NULL;
  msg.msg_namelen = 0;
  msg.msg_iov = iov;
  msg.msg_iovlen = 1;
  msg.msg_controllen = CMSG_SPACE(sizeof(int));
  msg.msg_control = ctrl_buf;

  cmsg = CMSG_FIRSTHDR(&msg);
  cmsg->cmsg_level = SOL_SOCKET;
  cmsg->cmsg_type = SCM_RIGHTS;
  cmsg->cmsg_len = CMSG_LEN(sizeof(int));

  *((int*) CMSG_DATA(cmsg)) = fd;

  return sendmsg(sock, &msg, 0);
}

int main(int argc, char **argv) {
  int c = socket(AF_UNIX, SOCK_STREAM, 0);
  assert(c != -1);

  struct sockaddr_un a;
  a.sun_family = AF_UNIX;
  strcpy(a.sun_path, "/service/sock");

  assert(connect(c, (struct sockaddr*) &a, sizeof(a)) != -1);

  sendfd(c, 0);
  sendfd(c, 1);

  close(c);

  /* The SSH conn should stay after returning, but it doesn't. */
}

server.c (process B):

#include
#include
#include
#include
#include
#include
#include

int recvfd(int socket) {
  int len;
  int fd;
  char buf[1];
  struct iovec iov;
  struct msghdr msg;
  struct cmsghdr *cmsg;
  char cms[CMSG_SPACE(sizeof(int))];

  iov.iov_base = buf;
  iov.iov_len = sizeof(buf);

  msg.msg_name = 0;
  msg.msg_namelen = 0;
  msg.msg_iov = &iov;
  msg.msg_iovlen = 1;
  msg.msg_flags = 0;
  msg.msg_control = (caddr_t) cms;
  msg.msg_controllen = sizeof(cms);

  len = recvmsg(socket, &msg, 0);

  if(len <= 0) {
return -1;
  }

  cmsg = CMSG_FIRSTHDR(&msg);
  memmove(&fd, CMSG_DATA(cmsg), sizeof(int));

  return fd;
}

int main(int argc, char **argv) {
  unlink("/service/sock");

  int s = socket(AF_UNIX, SOCK_STREAM, 0);
  assert(s != -1);

  struct sockaddr_un a;
  a.sun_family = AF_UNIX;
  strcpy(a.sun_path, "/service/sock");
  assert(bind(s, (struct sockaddr*) &a, sizeof(a)) != -1);

  assert(chmod("/service/sock", 0777) != -1); /* Quick workaround. */

  assert(listen(s, 20) != -1);

  while(1) {
puts("Waiting..");

int c = accept(s, NULL, NULL);
assert(c != -1);

puts("Accepted");

int in = recvfd(c);
int out = recvfd(c);

printf("Received: in=%i out=%i\n", in, out);

char *outstr = "Hello from the Server\n";
assert(write(out, outstr, strlen(outstr)) != -1);

assert(close(c) != -1);

/* Intentionally leaking SSH FDs */
  }
}

Compiled with:
  cc -std=c99 -o server server.c
  cc -std=c99 -o client client.c

`client` is also the shell of the user, but the results are the same if
I call it from within a "real" shell, too.

The server receives the correct FDs, and prints
"Hello from the Server\n" correctly, too. But as soon as `client`
exits, the SSH connection goes with it, instead of staying (as in,
I get "Connection to localhost closed").



Re: Transferring ownership of SSH connection from process A to B, letting A quit nicely?

2021-08-08 Thread Philip Guenther
On Sun, Aug 8, 2021 at 10:13 AM mid  wrote:
...

> I have tried sending the file descriptors associated with the connection
> to process B via sendmsg, thinking that maybe the
> file descriptors are reference-counted. It's a logical
> assumption, but it didn't work - the connection closed with
> process A.
>

File descriptors sent via sendmsg() on a unix domain socket of SCM_RIGHTS
control messages *are* reference-counted.

If you think you've done that and it's not behaving as expected, then first
check and report errors on *all* the system calls, and that the returned
data fields on things like recvmsg() have the values you expect.  If
sendmsg() is failing or you're accidentally discarding the fds in the
recvmsg() by not providing the space needed then yeah, the fds will be
closed because the last reference is gone.

If you're 100% sure you have it right, then it should be easy to provide a
program that demonstrates
1) passing an fd between processes
2) using it *successfully* in the receiving process
3) the sending process exiting
3) attempts to us it failing the receiving process

No?


Philip

(Replies not on the list will be deleted)


Transferring ownership of SSH connection from process A to B, letting A quit nicely?

2021-08-08 Thread mid
Hello. I have an interesting conundrum I'm dealing with, and
would like some ideas on getting it to work.

I'm making a useless service for recreational purposes,
and it involves holding many SSH connections at once. Ideally
said service should be composed of only one process, accepting multiple 
clients, since they interact with each other in (mostly)
real-time, unlike a typical web server.

But because of how SSH works, each connection sits behind yet
another process. I'd have to employ some IPC for it to work,
but would end up making it a lot less scalable. What I wanted was
so that each connection would invoke the SSH shell (process A),
and said shell would somehow pass ownership of the connection
to the main server process (process B). Afterwards, process A
could safely exit, leaving the SSH connection intact. This would
mean process B would be in charge of multiple SSH connections.

I have tried sending the file descriptors associated with the connection to 
process B via sendmsg, thinking that maybe the
file descriptors are reference-counted. It's a logical
assumption, but it didn't work - the connection closed with
process A.

I have also tried opening a /dev/ttyp* file corresponding to the connection, 
but that didn't work either. So is this not possible under OpenBSD's semantics?

Scalability is not a real issue, but having IPC adds a load
of complexity I'd rather not get involved with.

Thanks.