I have a custom shell, which runs in one process. I want to use the inbuilt ssh available in Linux. I want to redirect the user I/O from the custom CLI to the actual linux shell.
Here is what I have done to do ssh:
INT4 do_ssh(tCliHandle CliHandle, CHR1 *destIp)
{
FILE *writePipe = NULL;
char readbuff[1024];
char cmd[1024];
memset(cmd,'\0',sizeof(cmd));
sprintf(cmd,"/usr/bin/ssh %s",destIp);
printf("cmd = %s\r\n",cmd);
writePipe = popen(cmd,"w");
if(writePipe == NULL)
{
return -1;
}
while( fgets(readbuff,sizeof(readbuff) - 1, writePipe) != NULL)
{
CliPrintf(CliHandle,"%s\r\n", readbuff);
//printf("%s",readbuff);
}
printf("Closing writePipe\r\n");
pclose(writePipe);
return 0;
}
The problem, which I see is that after doing ssh I can't see the session anymore.
Here is the output:
cust# ssh 192.168.10.42
cmd = /usr/bin/ssh 192.168.10.42
Closing writePipe
Pseudo-terminal will not be allocated because stdin is not a terminal.
Could not create directory '/root/.ssh'.
root#192.168.10.42's password:
ssh 192.168.10.42
My expectation is to keep the session alive and let the user keep sending the command from the terminal and it should get printed on the terminal.
But, I see that after ssh the session is closed. I want to keep it open.
I want to close only when the window is closed or exit is passed.
What I should do? Any hints will be helpful.
Related
I think I'm running the same functionality in a C program as on the console, but I have permissions problems setting a GPIO direction.
These console commands, run as a normal user, work fine:
$ echo 436 > /sys/class/gpio/export
$ echo out > /sys/class/gpio/gpio436/direction
... while this code, in a C program (which I intend to have the same effect), fails:
...
int gpioNumber = 436;
/* Successful open... */
FILE *exportNode = fopen("/sys/class/gpio/export", "w");
if (exportNode == NULL) {
printf("Unable to open /sys/class/gpio/export\n");
return CT_GPIO_FAIL;
}
char buffer[100];
sprintf(buffer,"%i",mGpioNumber);
if (fprintf(exportNode, buffer) != (strlen(buffer)))
{
printf("Error writing to /sys/class/gpio/export\n");
return CT_GPIO_FAIL;
}
fclose(exportNode);
/* At this point the node /sys/class/gpio/gpio436 exists - I can see it in the console. */
// Set the pin to be input or output by writing "out" to /sys/class/gpio/gpio[xx]/direction
// I think this is the same file as gets opened in the second shell command.
printf("About to open direction.\n");
sprintf(buffer,"/sys/class/gpio/gpio%i/direction",mGpioNumber);
/* This line fails! */
FILE *directionNode = fopen(buffer, "w");
/* .. and the error is reported. */
if (directionNode == NULL) {
int errnum = errno;
printf("Unable to open %s. Last error: %s\n",buffer,strerror(errnum));
return CT_GPIO_FAIL;
}
This is the error report:
Unable to open /sys/class/gpio/gpio436/direction. Last error: Permission denied
If the direction node hasn't been created, I get a different error, so the reported permissions error seems to be accurately reported.
I run the program from the same console as the shell commands (after unexporting the GPIO, but without any other intervening actions. The program runs without error using sudo.
Why aren't the permissions issues the same inside this C program run from the console, as they are in shell commands? Am I missing a simple code error?
This is all running on a Jetson Xavier NX, Ubuntu 18.04.4 LTS
Well ... It does work as written, with the addition of a few milliseconds of sleep between "export" and trying to open the direction node. Apparently the creation of the direction node isn't synchronous in the write to export, at least on this system.
I apologize for the noise.
I want to automate the mounting of a sshfs connection inside my C program (meant for linux) using only password for ssh. (I don't want to use public/private keys.)
It seems i could do it with libexpect. Based on this thread it seems possible to use libexpect to give the password when required. For example, i made a successful test program that creates a dir with sudo mkdir test and then provide the user password with libexpect. So that pipe seems really to be bidirectional. Thou, with sshfs and my simple function below, it doesn't work: i do have a sshfs mount produced by it, but it doesn't work and i can't see the files.
enum{ASKCONTINUE,ASKPWD};
int sshfs_connect (char data[10][200], char ip[]) {
char commandline[300];
sprintf(commandline,"sshfs %s#%s:%s %s -p %s -o ServerAliveInterval=15",
data[4],ip,data[6],data[5],data[7]);
bool shouldBreak = false;
FILE* fp = exp_popen(commandline);
while(shouldBreak == false)
{
switch(exp_fexpectl(fp,
//if asked for continuing (authenticity can't be established)
exp_glob, "ontinue connecting (yes/no)?", ASKCONTINUE,
//if asked for pwd
exp_glob, "s password:", ASKPWD,
exp_end)) //
{
case ASKCONTINUE:
printf("asked continue? !\n");
fprintf(fp,"%s\n","yes");
break;
case ASKPWD:
printf("asked pwd ! sending pwd: %s\n",data[8]);
fprintf(fp,"%s\n",data[8]);
shouldBreak = true;
break;
case EXP_TIMEOUT:
shouldBreak = true;
break;
case EXP_EOF:
shouldBreak = true;
break;
}
}
fclose(fp);
return 0;
}
It seems that expect (even the tcl version) cannot be used with sshfs, probably because the spawned process does not have a controlling tty and so the command tries to get the password from the user by other means, e.g. using a gui popup.
What works is adding the option -o password_stdin to ask sshfs to read the password from stdin. It does this without writing a prompt, so libexpect is a bit heavyweight, but nonetheless this should work for you: send the password and wait for eof (which would probably be within the default timeout of 10 seconds).
ssh = exp_popen("sshfs -o password_stdin user#host:/dir /mntpoint");
if(ssh==NULL)fatal("fail to spawn");
fprintf(ssh, "%s\n", password);
switch(exp_fexpectl(ssh,exp_end)) {
case EXP_EOF:
break; // ok
case EXP_TIMEOUT:
break; // fail
default:
break; // fail
}
I am writing pager pspg. There I have to solve following issue. After reading from stdin I should to reassign stdin from previous reading from pipe to reading from terminal.
I used
freopen("/dev/tty", "r", stdin)
But it doesn't work, when pager was used from command what was not executed directly
su - someuser -c 'export PAGER=pspg psql somedb'
In this case, I got a error: No such device or address.
I found a workaround - now, the code looks like:
if (freopen("/dev/tty", "r", stdin) == NULL)
{
/*
* try to reopen pty.
* Workaround from:
* https://cboard.cprogramming.com/c-programming/172533-how-read-pipe-while-keeping-interactive-keyboard-c.html
*/
if (freopen(ttyname(fileno(stdout)), "r", stdin) == NULL)
{
fprintf(stderr, "cannot to reopen stdin: %s\n", strerror(errno));
exit(1);
}
}
What is a correct way to detect assigned terminal device in this case?
But this workaround is not correct. It fixed one issue, but next is comming. When someuser is different than current user, then reopen fails with error Permission denied. So this workaround cannot be used for my purposes.
What less does in this situation is fall back to fd 2 (stderr). If stderr has been redirected away from the tty, it gives up on trying to get keyboard input, and just prints the whole input stream without paging.
The design of su doesn't allow for anything better. The new user is running a command on a tty owned by the original user, and that unpleasant fact can't be entirely hidden.
Here's a nice substitute for su that doesn't have this problem:
ssh -t localhost -l username sh -c 'command'
It has a little more overhead, of course.
On the end I used pattern that I found in less pager, but modified for using with ncurses:
First I try to reopen stdin to some tty related device:
if (!isatty(fileno(stdin)))
{
if (freopen("/dev/tty", "r", stdin) != NULL)
noatty = false;
/* when tty is not accessible, try to get tty from stdout */
else if (freopen(ttyname(fileno(stdout)), "r", stdin) != NULL)
noatty = false;
else
{
/*
* just ensure stderr is joined to tty, usually when reopen
* of fileno(stdout) fails - probably due permissions.
*/
if (!isatty(fileno(stderr)))
{
fprintf(stderr, "missing a access to terminal device\n");
exit(1);
}
noatty = true;
fclose(stdin);
}
}
else
noatty = false;
When I have not tty and cannot to use stdin, then I am using newterm functions, that allows to specify input stream:
if (noatty)
/* use stderr like stdin. This is fallback solution used by less */
newterm(termname(), stdout, stderr);
else
/* stdin is joined with tty, then use usual initialization */
initscr();
I am currently trying to use the pulseaudio simple API to record microphone data from my USB sound card with my raspberry pi 3. I used the example program parec-simple from pulseaudio in my own program and it works quite nice.
The program i used this code for is accessing gpio's so i need to run this as root. However, when i try to execute the program as root, i get the following errors:
Home directory not accessible: Permission denied
W: [pulseaudio] core-util.c: Failed to open configuration file '/root/.config/pulse//daemon.conf': Permission denied
W: [pulseaudio] daemon-conf.c: Failed to open configuration file: Permission denied
pa_simple_new() failed: Connection refused
the code is used is the following:
static const pa_sample_spec ss = {
.format = PA_SAMPLE_S16LE,
.rate = 44100,
.channels = 1
};
pa_simple *s = NULL;
int ret = 1;
int error;
/* Create the recording stream */
if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, NULL, &error))) {
fprintf(stderr, "pa_simple_new() failed: %s\n", pa_strerror(error));
goto finish;
}
while(1)
{
uint8_t buf[BUFSIZE];
/* Record some data ... */
if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) {
fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error));
goto finish;
}
/* And write it to STDOUT */
if (loop_write(STDOUT_FILENO, buf, sizeof(buf)) != sizeof(buf)) {
fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno));
goto finish;
}
}
ret = 0;
finish:
if (s)
pa_simple_free(s);
return ret;
I already tried chown pi:pi /home/pi as suggested here to try to fix it but it doesn't work. changing the owner of /home/pi from pi to root didn't work for me either.
I also tried a clean reinstall of pulseaudio but unfortunately it didn't fix it.
So what can i do to fix these errors?
If you need to run your program as user root, then you must impersonate root. I don't know if pulseaudio looks at the username in order to find configuration files, or it looks at the $HOME variable. In the second case, maybe that by setting HOME to the home of a "working" user helps.
Anyway what you told about the situation is clear: pulseaudio does not find a file:
'/root/.config/pulse//daemon.conf'
Place a correct "daemon.conf" in that directory - probably you can copy it from somewhere (like /home/auser/.config/pulse/daemon.conf).
Consider that directories with name starting with a dot are normally hidden; if using a file manager you must enable "show hidden files", if you use the shell, ls -a can help.
Your first target is to confirm that the file is there, and your program should not complain about a missing/unreadable config file. Then, maybe other errors will show up but, one after another, you can eliminate them.
When you run process with sudo it does not change Home directory to /root - sudo echo $HOME # /home/username. You need to specify HOME directory with by running sudo HOME=/root executable.
When you want to access pulseaudio from root you need to run it system wide with command - sudo pulseaudio --system=true.
Then you will receive an error from pulseaudio:
W: [pulseaudio] protocol-native.c: Denied access to client with invalid authentication data.
Which can be solved by adding root user to audio-pulse group - sudo adduser root pulse-access.
I'm currently writing a program that will run multiple commands (in one line) in the CLI using C.
The first command that I need to run is sudo -s. So I run this command alone to test if the program is running, but the program hangs while running this command. I wanted to know if the problem is the program or the command, so I run ls. The program works perfectly when I run the ls command so I assume that something is wrong with sudo -s command, maybe I need to do something with that command so that it will run in the CLI.
Here's the function that accepts the command:
int executeCommand(char *command, char *result)
{
/*This function runs a command./*/
/*The return value is the output of command*/
int nSuccess = -1;
FILE * fp = NULL;
char buffer[1035];
if (command == NULL)
render("Command is null");
if (result == NULL)
render("result is null");
if (command!=NULL && result!=NULL)
{
fp=popen(command,"r");
if(fp!=NULL)
{
strcpy(result,"\0");
while(fgets(buffer, sizeof(buffer)-1,fp)!=NULL)
{
strcat(result,buffer);
}
pclose(fp);
} nSuccess=0;
}
return nSuccess;
}
BTW, I'm doing a web app, the user will write the command that he wants to execute. The input will be sent to server via ajax using a POST request. And the server runs on Linux.
sudo -s
will require the password so the program running this command may wait for password to be entered
sudo -s will prompt for a password and won't return a result immediately.