LINUX.ORG.RU

[QT] QProcess & SSH. Pseudo ttys ? Как ?

 


0

0

Здрасьте.

Помогите пожалуйста решить такую задачку. Надо как-то взаимодействовать с SSH через QProcess что-бы например отловить запрос пароля (я знаю что возможна авторизация по ключам, не в этом дело), или надо какую-то клавиатурную комбинацию над этим процессом совершить

Я слышал что мне должны помочь псевдо-терминалы, но я совсем не знаю как их использовать. Ситуация усугубляется тем что очень мало документации в инете по этому вопросу(только man да ещё и на английском). Я также не нашёл ни одного примера..

Поделитесь мыслями плиз...

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/stropts.h>

int main(int argc, char* argv[])
{
int fdm, fds;
char *slavename;
extern char *ptsname();

fdm = open("/dev/ptmx", O_RDWR); /* open master */
grantpt(fdm); /* change permission of slave */
unlockpt(fdm); /* unlock slave */
slavename = ptsname(fdm); /* get name of slave */
fds = open(slavename, O_RDWR); /* open slave */
ioctl(fds, I_PUSH, "ptem"); /* push ptem */
ioctl(fds, I_PUSH, "ldterm"); /* push ldterm */
printf("slavename=%s fdm=%d fds=%d\n", slavename, fdm, fds);

// что дальше то делать ???

return 0;
}

$ gcc -o test test.c
$ ./test
slavename=/dev/pts/1 fdm=3 fds=4

По материалам http://ou800doc.caldera.com/en/SDK_sysprog/_Pseudo-tty_Drivers_em_ptm_and_p.html:
> Unrelated processes may open the pseudo-device. The initial user
> may pass the master file descriptor using a STREAMS-based pipe or
> a slave name to another process to enable it to open the slave.

Мой вольный перевод:
> Любой процесс может открыть это псевдо-устройство. Первоначальный
> пользователь может передать дескриптор fds используя именованный
> канал или значение переменной "slavename" другому процессу чтобы
> разрешить ему открыть slave

Это как понять ? Как я могу процессу SSH это передать ???

anterior
() автор топика
Ответ на: комментарий от anterior

// что дальше то делать ???

дальше делать fork. В child-е dup2(fds, 0), dup2(fds, 1), dup2(fds, 2), execl. В родителе select (fds...)/read/write/waitpid.

Но похоже имеено для ssh это не сработает. Почитай вот здесь: http://www.derkeiler.com/Mailing-Lists/securityfocus/Secure_Shell/2003-11/011...

phoenix ★★★★
()
Ответ на: комментарий от phoenix

Спасибо! Вроде работает. А в какой дескриптор надо писать чтобы 
записать в STDIN потомка ? На примере того же telnet'a:

  int fdm, fds;
  char *slavename;
  extern char *ptsname();

  fdm = open("/dev/ptmx", O_RDWR); /* open master */
  grantpt(fdm); /* change permission of slave */
  unlockpt(fdm); /* unlock slave */
  slavename = ptsname(fdm); /* get name of slave */
  fds = open(slavename, O_RDWR); /* open slave */
  ioctl(fds, I_PUSH, "ptem"); /* push ptem */
  ioctl(fds, I_PUSH, "ldterm"); /* push ldterm */

  pid_t pID = fork();
  if (pID == 0) { // child
    dup2(fds, 0);
    dup2(fds, 1);
    dup2(fds, 2);
//     execl("/usr/bin/ssh", "/usr/bin/ssh", "kde-devel@localhost", (char*)0);
//     execl("/bin/sh", "/bin/sh", "-c", "SSH_ASKPASS=ggg.sh /usr/bin/ssh kde-devel@localhost", (char*)0);
    execl("/usr/bin/telnet", "/usr/bin/telnet", (char*)0);
  }
  else if (pID > 0) { // parent
    fd_set rfds;
    struct timeval tv;
    int retval;
    FD_ZERO(&rfds);
    FD_SET(fdm, &rfds);
    tv.tv_sec = 5;
    tv.tv_usec = 0;
    retval = select(fds, &rfds, NULL, NULL, &tv);
    if (retval) {
      char buf[200] = "\0";
      read(fdm, buf, 199);
      printf("OUT:\n%s\n", buf);
      strcpy(buf, "quit\n");
      write(fdm, buf, strlen(buf)+1); // пишу команду выхода
    }
    else
      printf("Данные не появились в течение пяти секунд.\n");
  }
  else
    return -1;

Смотрю:
$ gcc -o test test.c
$ ls /dev/pts
0
$ ./test
OUT:
telnet>
$ ls /dev/pts
0  1
$ killall telnet
$ ls /dev/pts
0

???

anterior
() автор топика
Ответ на: комментарий от anterior

> select(fds, &rfds, NULL, NULL, &tv)

здесь должно быть select(fdm+1, &rfds, NULL, NULL, &tv)

Не могу сказать, почему повисает telnet. Если заменить его на 

execl("/usr/bin/perl", "/usr/bin/perl", "-e", "print 'test'; <STDIN>;", (char*)0);

то работает как нужно.

BTW, имеет смысл посмотреть в сторону expect.

phoenix ★★★★
()
Ответ на: комментарий от phoenix

Да уж действительно... с перлом работает, да и с /bin/sh тоже..

ладно, будем ковырятся дальше...

anterior
() автор топика
Ответ на: комментарий от phoenix

> Не могу сказать, почему повисает telnet.

Судя по всему из-за того что не все данные были считаны из fdm...

По-крайней мере если делать так:
// === start command
  tv.tv_sec = 1;
  tv.tv_usec = 0;
  FD_ZERO(&rfds);
  FD_SET(fdm, &rfds);
  write(fdm, "quit\n", 6);
  while (select(fdm+1, &rfds, NULL, NULL, &tv) > 0) {
    cc = read(fdm, buf, sizeof(buf));
    write(0, buf, cc);
  }
//=== end command

То с этим вариантом ничего не подвисает

anterior
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.