libcli icon indicating copy to clipboard operation
libcli copied to clipboard

libcli without telnet

Open jchoi999 opened this issue 9 years ago • 10 comments

Hi Is there any way I can use libcli without using telnet? I'm wondering it is possible that run a program like clitest and it displays login screen directly without using telnet session and access cli commands.

Thanks,

jchoi999 avatar Jan 23 '17 22:01 jchoi999

You technically could. But the whole library was designed around handling telnet codes for controlling the cursor, etc.

On Tue, Jan 24, 2017 at 9:07 AM, jchoi999 [email protected] wrote:

Hi Is there any way I can use libcli without using telnet? I'm wondering it is possible that run a program like clitest and it displays login screen directly without using telnet session and access cli commands.

Thanks,

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/dparrish/libcli/issues/27, or mute the thread https://github.com/notifications/unsubscribe-auth/AAL0QzJEP7-XrB0K9IZPkdg7G9G3qHTKks5rVSSEgaJpZM4LrmyD .

dparrish avatar Jan 24 '17 03:01 dparrish

Thank you for your reply! I was thinking I could use libcli to write an application which is receiving user input from the local machine without going through remote session.

Do you have any recommendation for this? Thanks!

On Mon, Jan 23, 2017 at 10:54 PM, David Parrish [email protected] wrote:

You technically could. But the whole library was designed around handling telnet codes for controlling the cursor, etc.

On Tue, Jan 24, 2017 at 9:07 AM, jchoi999 [email protected] wrote:

Hi Is there any way I can use libcli without using telnet? I'm wondering it is possible that run a program like clitest and it displays login screen directly without using telnet session and access cli commands.

Thanks,

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/dparrish/libcli/issues/27, or mute the thread <https://github.com/notifications/unsubscribe-auth/AAL0QzJEP7- XrB0K9IZPkdg7G9G3qHTKks5rVSSEgaJpZM4LrmyD> .

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/dparrish/libcli/issues/27#issuecomment-274698874, or mute the thread https://github.com/notifications/unsubscribe-auth/APZ9cCzQXB2tjcnM0UClJ3NvZ8Fy-ejxks5rVXXpgaJpZM4LrmyD .

jchoi999 avatar Jan 24 '17 22:01 jchoi999

clitest shows how that can be done I think.

On Wed, Jan 25, 2017 at 9:50 AM, jchoi999 [email protected] wrote:

Thank you for your reply! I was thinking I could use libcli to write an application which is receiving user input from the local machine without going through remote session.

Do you have any recommendation for this? Thanks!

On Mon, Jan 23, 2017 at 10:54 PM, David Parrish [email protected] wrote:

You technically could. But the whole library was designed around handling telnet codes for controlling the cursor, etc.

On Tue, Jan 24, 2017 at 9:07 AM, jchoi999 [email protected] wrote:

Hi Is there any way I can use libcli without using telnet? I'm wondering it is possible that run a program like clitest and it displays login screen directly without using telnet session and access cli commands.

Thanks,

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/dparrish/libcli/issues/27, or mute the thread <https://github.com/notifications/unsubscribe-auth/AAL0QzJEP7- XrB0K9IZPkdg7G9G3qHTKks5rVSSEgaJpZM4LrmyD> .

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/dparrish/libcli/issues/27#issuecomment-274698874, or mute the thread <https://github.com/notifications/unsubscribe-auth/ APZ9cCzQXB2tjcnM0UClJ3NvZ8Fy-ejxks5rVXXpgaJpZM4LrmyD> .

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/dparrish/libcli/issues/27#issuecomment-274965042, or mute the thread https://github.com/notifications/unsubscribe-auth/AAL0Q0R2S4uegtbp7MM78PuL_55_a1ZIks5rVoA9gaJpZM4LrmyD .

dparrish avatar Jan 25 '17 01:01 dparrish

OK. Thanks!

On Tue, Jan 24, 2017 at 8:04 PM, David Parrish [email protected] wrote:

clitest shows how that can be done I think.

On Wed, Jan 25, 2017 at 9:50 AM, jchoi999 [email protected] wrote:

Thank you for your reply! I was thinking I could use libcli to write an application which is receiving user input from the local machine without going through remote session.

Do you have any recommendation for this? Thanks!

On Mon, Jan 23, 2017 at 10:54 PM, David Parrish < [email protected]> wrote:

You technically could. But the whole library was designed around handling telnet codes for controlling the cursor, etc.

On Tue, Jan 24, 2017 at 9:07 AM, jchoi999 [email protected] wrote:

Hi Is there any way I can use libcli without using telnet? I'm wondering it is possible that run a program like clitest and it displays login screen directly without using telnet session and access cli commands.

Thanks,

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/dparrish/libcli/issues/27, or mute the thread <https://github.com/notifications/unsubscribe-auth/AAL0QzJEP7- XrB0K9IZPkdg7G9G3qHTKks5rVSSEgaJpZM4LrmyD> .

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/dparrish/libcli/issues/27#issuecomment-274698874, or mute the thread <https://github.com/notifications/unsubscribe-auth/ APZ9cCzQXB2tjcnM0UClJ3NvZ8Fy-ejxks5rVXXpgaJpZM4LrmyD> .

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/dparrish/libcli/issues/27#issuecomment-274965042, or mute the thread <https://github.com/notifications/unsubscribe- auth/AAL0Q0R2S4uegtbp7MM78PuL_55_a1ZIks5rVoA9gaJpZM4LrmyD>

.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/dparrish/libcli/issues/27#issuecomment-274989614, or mute the thread https://github.com/notifications/unsubscribe-auth/APZ9cHFfKwA9qvtN2DNrO56LC0P3ZqpAks5rVp-6gaJpZM4LrmyD .

jchoi999 avatar Jan 25 '17 23:01 jchoi999

I'm also interested in running libcli-based programs locally, without sockets or telnet.

I tried the "simple" hack of passing stdin as socket to cli_loop(), and it almost works: I can see the output of libcli, and I can type stuff into libcli (e.g. ? is interpreted). However, completion is not working, and pressing Enter doesn't do anything.

Based on #39 I found a workaround with stty, it was just missing -icrnl to convert newlines to \r\n.

Here is the invocation:

stty_orig="$(stty -g)" ; stty -echo -icanon -icrnl ; ./localcli ; stty $stty_orig

And here is the entire C code of localcli.c:

#include "libcli.h"

int main() {
 struct cli_def *cli;

 cli = cli_init();
 cli_set_banner(cli, "libcli test environment");
 cli_set_hostname(cli, "router");
 cli_telnet_protocol(cli, 0);

 cli_register_command(cli, NULL, "simple", NULL, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL);

 /* Hack: pass stdin as socket */
 cli_loop(cli, 0);
 cli_done(cli);

 return 0;
}

zorun avatar Aug 20 '20 21:08 zorun

While I'm happy it works, this is really a hack. Would there be a better way to do this?

I've thought about forking and creating a socket pair to communicate between parent and child (similar to what @RobSanders proposed in #42 ). However, I'm not sure how it would solve issues such as the lack of \r\n? The parent would need to convert \n to \r\n before writing data to the socket, and probably other adaptations?

zorun avatar Aug 20 '20 21:08 zorun

Libcli was written assuming telnet style I/O, which I believe is different than if you were simply reading stdin or a socket (and may vary OS to OS to boot). Not sure I tested the completions fully in #39 , just basic 'enter the commandline'. The fork method we're doing in #42 was more for our application. As mentioned there, we have our libcli app as the default shell for certain users. Our 'front end' processes monitors stdin and copies that data to the 'back end' process process socket, where libcli takes over. We were not allowed to have 'direct' access between out application and the outside world.

RobSanders avatar Aug 21 '20 16:08 RobSanders

Ok, thanks @RobSanders

Letting libcli interpret terminal "special codes" seems to work quite well in the few terminal emulators I tested.

The hack with stty can be done directly in C. It's actually almost equivalent to putting the terminal in "raw" mode. Here is the code, very slightly adapted from http://kirste.userpage.fu-berlin.de/chemnet/use/info/libc/libc_12.html#SEC250 :

#include <termios.h>

/* Saves the original terminal attributes. */
struct termios saved_termios;

void set_input_mode(void)
{
    struct termios tattr;

    /* Make sure stdin is a terminal. */
    if (!isatty(STDIN_FILENO))
    {
	fprintf(stderr, "Not a terminal.\n");
	exit(EXIT_FAILURE);
    }

    /* Save the terminal attributes so we can restore them later. */
    tcgetattr(STDIN_FILENO, &saved_termios);
    atexit(reset_input_mode);

    /* Set the funny terminal modes. */
    tcgetattr(STDIN_FILENO, &tattr);
    tattr.c_lflag &= ~(ICANON|ECHO);       /* Clear ICANON and ECHO. */
    tattr.c_iflag &= ~(ICRNL);             /* Clear ICRNL. */
    tattr.c_cc[VMIN] = 1;
    tattr.c_cc[VTIME] = 0;
    tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr);
}

I'm still having trouble with restoring the saved terminal attributes on exit. Bash does it automatically, but only when quitting with Ctrl-C. When exiting with Ctrl-D, bash does nothing special and leaves the terminal in a broken state (no echo). Even restoring the saved terminal attributes with tcsetattr on exit does nothing... I guess it depends both on the shell and the terminal emulator.

zorun avatar Aug 23 '20 16:08 zorun

Thank you for your posts here @zorun. I figured out why restoring the terminal attributes wasn't working. It turns out that cli_loop() closes the file descriptor on exit! So when you call tcsetattr(STDIN_FILENO,...) to restore the terminal attributes, it will not work. My workaround is to dup() and pass the result to cli_loop() like so:

int fd = dup(STDIN_FILENO); 
set_input_mode();
cli_loop(cli, fd);

cooljake777 avatar May 24 '21 19:05 cooljake777

@dparrish would you accept a pull request that adds this?

Either we could check if the fd passed to cli_run() is a socket or we could use a flag like telnet_protocol.

But the whole library was designed around handling telnet codes for controlling the cursor

It's libcli tho, not libtelnetcli ;-) It almost works with stdin/stdout/stderr with just minor changes. And I think telnet_protocol is already there for turning telnet stuff off, isn't it?

libcli is awesome and it would be super nice if it worked with non-socket fd's.

heeplr avatar Nov 04 '23 09:11 heeplr