howto Enter into chroot environment from C? - c

what i am try to do is to get my program to enter chroot environment and do some commands and then exit.
For Example
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define ChRoot "sudo chroot \"/\" /usr/bin/env -i HOME=/root TERM=\"$TERM\" PATH=/bin:/usr/bin:/sbin:/usr/sbin:/bin /bin/bash --login +h"
void func1(){
//enter the chroot environment
char line[130]; FILE *fp;
fp = popen(ChRoot, "r");
while(fgets( line, sizeof line, fp)){
printf ("%s\n",line);
}
pclose(fp);
}
void func2(){
//run a command in the chroot environment
char line[130]; FILE *fp;
fp = popen("ls", "r");
while(fgets( line, sizeof line, fp)){
printf ("%s\n",line);
}
pclose(fp);
}
int main() {
func1();
func2();
return 0;
}
the problem with this code is, it will get me in the chroot environment however it will not fire func2 until i exit form the chroot environment. What i need is to get my code to do func1 and then func2 in chroot environment and then exit.I know what i am doing in my code is horribly wrong, however, i hope i could get some directions .
Any help would be much appreciated.

If you're in C and you want to enter a chroot you can do so directly using the chroot() function:
#include <stdio.h>
#include <unistd.h>
int main(void) {
FILE *f;
/* chroot */
chdir("/tmp");
if (chroot("/tmp") != 0) {
perror("chroot /tmp");
return 1;
}
/* do something after chrooting */
f = fopen("/etc/passwd", "r");
if (f == NULL) {
perror("/etc/passwd");
return 1;
} else {
char buf[100];
while (fgets(buf, sizeof(buf), f)) {
printf("%s", buf);
}
}
return 0;
}
Note that if you don't set the current directory before chrooting it's possible to break out of the chroot.

There is a chroot system call that does what you want. In fact, the chroot command-line utility itself uses this first and then spawns a shell.

Related

Redirect output of command line to a variable in C

Is there a way to redirect output of a command line which returns integer as an output to a variable in C?
for example, if the command is "cmd", then is there a way to redirect its output (an integer) and store it in variable in C?
I tried using popen and fgets but it seems to be working only with characters. Any suggestions?
It works perfectly fine with popen and fgets:
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
const char *cmd = argc > 1 ? argv[1] : "echo 42";
char buf[32];
FILE *fp = popen(cmd, "r");
if( fp == NULL ){
perror("popen");
return 1;
}
if( fgets(buf, sizeof buf, fp) == buf ){
int v = strtol(buf, NULL, 10);
printf("read: %d\n", v);
}
return 0;
}
If you want to convert a character string from the standard input, you could use fgets and then use atoi to convert the input to an integer.
If you want to convert the output of a command, let's say ls and store the output of the command to a variable, you could learn about fork, dup2, pipe, and exec function family.
More about this topic on this tutorial : Capture the output of a child in C. This tutorial also provide an example with popen if you want to keep things "high level".
Here is an even simpler example using popen() and fscanf():
#include <errno.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
FILE *fp = popen("date '+%s'", "r");
long seconds;
if (fp == NULL) {
fprintf(stderr, "popen failed: %s\n", strerror(errno));
return 1;
}
if (fscanf(fp, "%ld", &seconds) == 1) {
printf("epoch seconds: %ld\n", seconds);
pclose(fp);
return 0;
} else {
fprintf(stderr, "invalid program output\n");
pclose(fp);
return 1;
}
}

How to get device name on which a file is located from its path in c?

Let's say I have a file in Linux with this path:
/path/to/file/test.mp3
I want to know the path to its device. For example I want to get something like:
/dev/sdb1
How do I do this with the C programming language?
I know the terminal command to do it, but I need C functions that will do the job.
EDIT:
I have read this question before asking mine. It doesn't concretly mention code in C, it's more related to bash than to the C language.
Thanks.
You need to use stat on the file path, and get the device ID st_dev and match that to a device in /proc/partitions
Read this for how to interpret st_dev: https://web.archive.org/web/20171013194110/http://www.makelinux.net:80/ldd3/chp-3-sect-2
I just needed that inside a program I am writing...
So instead of running "df" and parsing the output, I wrote it from scratch.
Feel free to contribute!
To answer the question:
You first find the device inode using stat() then iterate and parse /proc/self/mountinfo to find the inode and get the device name.
/*
Get physical device from file or directory name.
By Zibri <zibri AT zibri DOT org>
https://github.com/Zibri/get_device
*/
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <libgen.h>
int get_device(char *name)
{
struct stat fs;
if (stat(name, &fs) < 0) {
fprintf(stderr, "%s: No such file or directory\n", name);
return -1;
}
FILE *f;
char sline[256];
char minmaj[128];
sprintf(minmaj, "%d:%d ", (int) fs.st_dev >> 8, (int) fs.st_dev & 0xff);
f = fopen("/proc/self/mountinfo", "r");
if (f == NULL) {
fprintf(stderr, "Failed to open /proc/self/mountinfo\n");
exit(-1);
}
while (fgets(sline, 256, f)) {
char *token;
char *where;
token = strtok(sline, "-");
where = strstr(token, minmaj);
if (where) {
token = strtok(NULL, " -:");
token = strtok(NULL, " -:");
printf("%s\n", token);
break;
}
}
fclose(f);
return -1;
}
int main(int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "Usage:\n%s FILE OR DIRECTORY...\n", basename(argv[0]));
return -1;
}
get_device(argv[1]);
return 0;
}
output is just the device name.
Example:
$ gcc -O3 getdevice.c -o gd -Wall
$ ./gd .
/dev/sda4
$ ./gd /mnt/C
/dev/sda3
$ ./gd /mnt/D
/dev/sdb1
$
Use this command to print the partition path:
df -P <pathname> | awk 'END{print $1}'

C:Program works fine but with gdb it crashes

I'm new in C and have some problem. Here is my code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int read_password(FILE *file, char *password, size_t n) {
fgets(password, n, file);
password[strcspn(password, "\n")] = '\0';
}
void elevated_shell(){
gid_t gid = getegid();
setresgid(gid,gid,gid);
fflush(stdout);
system("/bin/bash");
}
void regular_shell(){
gid_t gid = getgid();
setresgid(gid,gid,gid);
fflush(stdout);
system("/bin/bash");
}
int main(int argc, char **argv){
char flag[100];
char password[100];
FILE *file;
printf("Hi! Welcome to my secure shell software!\n");
// Read in the root password
file = fopen("flag.txt", "r");
if(file == NULL) {
printf("FAIL: Failed to open the password file\n");
return -3;
} else {
read_password(file, flag, sizeof(flag));
}
// Read in the user's password
printf("Please enter the password: ");
fflush(stdout);
read_password(stdin, password, sizeof(password));
if(strcmp(flag,password) == 0) {
printf("Correct! Here's an elevated shell :)\n");
elevated_shell();
} else {
printf("Incorrect! No elevated shell for you >:)\n");
regular_shell();
}
}
So, I've compiled this file and run. It works fine when I run it directly but whenever I try to examine memory with gdb it crashes. For example when breakpoint is set at main function and run program is run fopen function returns Null because program print out
FAIL: Failed to open the password file and quits. Hope you can help.
GDB uses the user privileges that runs the program (type whoami to get noticed) not by privileges that the program has.

Simulate the Linux command tee in C

I have to do the simulation of the command tee in C for Linux. How does tee work internally? It looks like a T-shaped pipe, so should I use a pipe? Is there a special kind of pipe?
tee takes stdin and copies the data stream to stdout as well as a file given as an option, it can be used in many very different situations.
An implementation in C is quite simple, just make a program that copies all data from stdin to stdout, but also use the same output statements for stdout on a file that you opened based on the command line argument.
basically in pseudo code:
file f = open(argv[1])
while (! end of file stdin) {
buffer = read stdin
write stdout buffer
write f buffer
}
close(f)
Note that you don't really have to do anything with pipes, your shell will sort out the pipes, the program only has to copy data from one stream to two others.
I finished the program!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
main(int argc, char *argv[]){
FILE *fp, *fp1;
char buffer;
if(argc != 4){
printf("\nError");
printf("\nSintaxis: tee [archivo1] [archivo2]\n");
exit(0);
}
if(strcmp(argv[1], "tee") == 0){
fp = fopen(argv[2], "r");
fp1 = fopen(argv[3], "w");
printf("\Content in %s:\n", argv[2]);
while(!feof(fp)){
buffer = fgetc(fp);
fputc(buffer, fp1);
printf("%c", buffer);
}
printf("\n\n%s received %s\n", argv[3], argv[2]);
fclose(fp);
fclose(fp1);
}
else
printf("\nThe first argument have to be tee\n");
}
Here is some code I wrote about 20 years ago to implement TEE in Windows. I have been using this with various batch files since then. Note the flush command at the end of each line.
#include <stdio.h>
#include <share.h>
int main (int argc, char * argv[])
{
if (argc < 2 )
{
printf ("Error: No output file name given, example: theCmd 2>&1 |ltee outputFileName \n");
return 1;
}
FILE *Out = _fsopen(argv[argc-1], "a", _SH_DENYWR);
if (NULL == Out)
{
char buf[300];
sprintf_s(buf, 300, "Error openning %s", argv[argc-1]);
perror(buf);
return 1;
}
int ch;
while ( EOF != (ch=getchar()))
{
putchar(ch);
putc(ch, Out);
if ( '\n' == ch )
fflush(Out);
}
_flushall();
fclose(Out);
return 0;
}

how would i create a file output stream in c like stdout?

if printf uses stdout but how would i write a print function using my own output stream? i want to handle this stream with a OO-like structure but i can do that myself. is this possible? this for learning.
would something like this work - i didnt test this code:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
FILE* stdout2 = NULL;
int init() {
stdout2 = fopen("stdout.txt", "w");
if (!stdout2) return -1;
return 1;
}
void print(char* fmt, ...) {
va_list fmt_args;
va_start(fmt_args, fmt);
char buffer[300];
vsprintf(buffer, fmt, fmt_args);
fprintf(stdout2, buffer);
fflush(stdout2);
}
void close() {
fclose(stdout2);
}
int main(int argc, char** argv) {
init();
print("hi"); // to console?
close();
return 0;
}
how would i get printf(char*, ...) print to the console? would i have to read the file in the same function?
Try use fdopen (see The GNU C Library: Descriptors and Streams).
#include <stdio.h>
int main(void) {
int filedes = 3; // New descriptor
FILE *stream = fdopen (filedes, "w");
fprintf (stream, "hello, world!\n");
fprintf (stream, "goodbye, world!\n");
fclose (stream);
return 0;
}
Compile with gcc as below, where 3 is the same as defined in filedes.
gcc -o teststream teststream.c && ./teststream 3> afile.txt && cat afile.txt
The result:
hello, world!
goodbye, world!
You can write to FILE*'s with fprintf, which will have the same semantics as printf.
int main(int argc, char** argv) {
init();
fprintf(stdout2,"hi"); // will print to file
close();
return 0;
}
If, inside init, you assign stdout to your own variable, the output will be to the console
void init() {
stdout2 = stdout;
if (!stdout2) return -1;
return 1;
}
Thats mostly correct. You should use functions that use length parameters though for security/overflow purposes. Secondly, the console (i.e. stdout) is simply a file descriptor with an id of 0, stderr is 1. You can open file descriptors with fdopen
int main(){
stdout2 = fdopen(stdout, "w");
print("Hello World"); //This will print to console
return 0;
}
This function will help you print to both the specified file and outstream (terminal). You have to specify the file pointer, and the rest is the usual format of printf.
void my_printf(FILE * fileptr, const char * string, ...){
char inBuf[100];
va_list args;
va_start(args, string);
vsprintf(inBuf, string, args);
fprintf(fileptr, inBuf);
printf("%s", inBuf);
va_end(args);
}
Example:
I/P:
my_printf( `file pointer`, "Hello World, today is \"%d\"th June", 10);
O/P:
Hello World, today is "10"th June

Resources