Open bash shell as root -script [duplicate] - c

This question already has an answer here:
How to run bash with root rights in C program?
(1 answer)
Closed 7 years ago.
I need to write a program in C which opens bash shell as root. I could not find a function which would be do that. I try something like that:
system("bash");
but i don't know what next

By default, your program will open a shell and run other programs as the same user which itself is running as. That is, if you run your program from a root account, it will execute other programs as root. Otherwise you can try this:
system("echo \"password\" | sudo -S bash"); # note the different quotes
But keep in mind that hard coding your password is highly inadvisable.

Since you asked how to do it in C, here's an idea how you could do it on Linux:
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main( void )
{
int pid = fork();
if ( pid == 0 )
{
# first argument: command to start ("sudo")
# second argument: program name for sudo ("$0" in shell)
# third argument: first argument to sudo, name of the command to execute as root
execlp( "sudo", "sudo", "bash", NULL );
}
int status;
// wait for bash to finish
wait( &status );
return 0;
}
Tested on Ubuntu 15.04.

Related

Running two commands using C and Linux environment variables

I'm trying to run two commands using a C program and a Linux environment variable:
#Program name is execute
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char cmd[256] = "/home/username/hello.sh $USER";
execl("/bin/bash", "bash", "-p", "-c", cmd, NULL);
return 0;
}
However, when running the program with the $USER environment variable set to a second command, the second command will not run.
env USER=";cat /home/username/hello.txt" ./execute
Hello from shell script
Hard coding the second command into the C program works:
char cmd[256] = "/home/username/hello.sh ;cat /home/username/hello.txt";
./execute
Hello from shell script
Hello from text file
I want my C program to return:
env USER=";cat /home/username/hello.txt" ./execute
Hello from shell script
Hello from text file
How can I get it to work, without changing the C program?
The only processing that's done on the result of expanding variables is word splitting and globbing. It doesn't process characters like ; to separate commands, > for output redirection, $ for further variable expansions, etc.
If you want to force a full parse of the command, you have to use eval.
char cmd[256] = "eval /home/username/hello.sh $USER";
execl("/bin/bash", "bash", "-p", "-c", cmd, (char*)NULL);

echo $PATH in system() give me a wrong output [duplicate]

This question already has answers here:
Difference between single and double quotes in Bash
(7 answers)
Closed 4 years ago.
This is a piece of code found on Internet
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
putenv("PATH=/nothinghere");
//setenv("PATH","/nothinghere");
system(argv[1]);
return 0;
}
if I do
$./a.out "ls"
sh: 1: ls: not found
Of course
But what if
$./a.out "echo $PATH"
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
It print the original $PATH !!
If we create a new shell then do the samethings
int main(int argc, char* argv[])
{
putenv("PATH=/nothinghere");
//setenv("PATH","/nothinghere");
system("/bin/sh");
return 0;
}
$./a.out
$ echo $PATH
/nothinghere
$ ls
/bin/sh: 2: ls: not found
Why?
Is it kind of problem about fork or the implementation of echo?
This is because you're using double quotes, telling your shell to replace $PATH with the value of the PATH variable before it even starts a.out.
The wrong value is thus being inserted not by the shell invoked by system(), but by the shell you're interactively typing commands at.
To fix it, change:
$ ./a.out "echo $PATH"
to:
$ ./a.out 'echo $PATH'

Why do we put exit(1) in the C code even knowing that it will terminate the program abnormally.

Why are we putting exit(1) to terminate the program abnormally? Why do we want to terminate abnormally?
//Program exits itself
//Note that the example would terminate anyway
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
cout<<"Program will exit";
exit(1); // Returns 1 to the operating system
cout<<"Never executed";
}
I think I see the problem. Saying that exit(1) terminates the program abnormally is not a very accurate statement, and can lead to confusion. A better way to say it is that exit(1) indicates unsuccessful termination, i.e., it lets the user of the program know that something went wrong. It's simply a way to communicate the problem.
I don't actually think this is such a bad question, it just indicates the confusion of someone new to coding.
The number that is returned from a C executable is returned to the environment.
If the SHELL is bash, you can capture the exit status of an executable with 'echo $?' from the command prompt.
Here is an example of a C code:
#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
FILE *fp;
if( ( fp = fopen( "nonexistfile", "r" ) )== NULL ){
exit(5);
}
if(fp) fclose(fp);
return 0;
}
This code is trying to open a file that does not exists. So it will exit with status of 5. Lets say the executable of this program is called "open_file".
When you run this executable and type "$?",
>./open_file
>echo $?
>5
Here a bash script that runs this executable:
#!/bin/bash
./open_file
exit_status="$?"
if [ $exit_status -eq 5 ]
then
echo "FILE not there"
fi
Now lets say you have 10 C executable programs that are similar to above C program but trying to open different files.
And lets say you want to keep a log file of which of these programs failed opening a file.
As a programmer, you can exit with different exit status number for different programs.
e.g. exit(1); for executable #1
exit(2); for executable #2
...
exit(10); for executable #10
From bash script, it can keep track of exactly which executable failed from return value of an executable.
This example was to illustrate how you can coordinate the exit(n); from a C program with bash script that runs this executable. (n represents a decimal value)
The reason is usually to tell the operating system something unusual happened. Typically, a program exits with a value of zero. In Linux, you can use $? to see the value returned (i.e. 'echo $?'). You can use this value in scripts, etc. to check how your program terminated.

How can I execute a Bash program from C? [duplicate]

This question already has an answer here:
Is it possible to include a shell script in a C program
(1 answer)
Closed 6 years ago.
How can I execute a command with bash? system() uses sh and not bash.
I know that I can execute commands in bash with system("/bin/bash -c command"). But I have a very long command and /bin/bash -c gives me problems. What I need is bashrun(command) or something else.
The command is a string, not a file
Case1 : script from a file - Use the shebang
#!/usr/bin/env bash
at the top of your script and then do
int status=system("/full/path/to/script");
if(status==-1){
// failure mode
}
Case2 : script stored as a string
Do something like below
char *command="$(which bash) -c 'ls'";
int status=system(command);
if (status==-1){
//failure mode
}
If you're creating a very long shell command and you need bash to interpret it, then you have two real options:
Save the text into a file and invoke bash with the filename as a single argument (equivalently, use a shebang in the file to specify bash as the interpreter, make the file executable, and invoke that as command), or
Start an instance of bash with popen() and write the shell command as standard input to the bash process.
If you're having problems due to shell script quoting (rather than the command length), then either of those options would work, or you could implement the equivalent of system() but using execl() to pass the argument without going through sh. I'm assuming a POSIX-type system here.
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int run_bash(const char *command)
{
int pid = fork();
if (pid < 0) {
/* failed */
perror("fork");
return pid;
} else if (pid == 0) {
/* child */
execl("/bin/bash", "bash", "-c", command, (char*)NULL);
perror("exec");
exit(EXIT_FAILURE);
} else {
/* parent */
int status;
do {
waitpid(pid, &status, 0);
} while (!WIFEXITED(status));
return WEXITSTATUS(status);
}
}
int main(void)
{
run_bash("echo '*'");
}

help with creating linux shell using C

I'm supposed to create a linux shell using C. Below is my code:
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define SHELL "/bin/sh"
#include "extern.h"
int mysystem (char *command)
{
int status;
pid_t pid;
pid = fork ();
if (pid == 0)
{
execl (SHELL, SHELL, "-c", command, NULL);
_exit (EXIT_FAILURE);
}
else if (pid < 0)
status = -1;
else
if (waitpid (pid, &status, 0) != pid)
status = -1;
return status;
}
Everything is right when I test the code using different commands like "ls", "man", etc. but when I use notepad to create a testfile containing the following:
echo "hello"
exit 2
the return code come out to be 512 when it's supposed to be just 2.
Can anyone help me fix my code?
status is not the exit code; it contains other information as well. Normally the return value is in bits 8-15 of status, but you should be using the macros in wait.h to extract the return value from status in a portable way.
Note that 512 is 2<<8.
Make sure you're using the macros like WIFEXITED and WEXITSTATUS on your status value. See your operating system's man page for waitpid. Here is a description of the POSIX requirements on waitpid.
By notepad do you mean you're using a Windows program to create a Unix shell script? That doesn't work because you end up with CRLF at the end of each line instead of LF. Try the "dos2unix" command on the script to convert it to Unix format and then run it.
I assume you're aware that code is already available in the system() library call? Judging by your function name, I'd guess you're just trying to learn how to do it with system calls.
Try enclosing your command string you supply to /bin/sh with quotes, because otherwise the space character makes /bin/sh think you are supplying another option to the shell itself, not to the command you are calling. For example, try this in a terminal:
/bin/sh -c exit 2
echo $?
and
/bin/sh -c "exit 2"
echo $?
The first one gives 0, and the second one gives the desired 2.

Resources