Why does posix_spawn() fail where popen() works? - c

I'm successfully using popen() to run commands from within my C program. As I understand, it uses fork() and exec() (or variants of those) behind the curtains. This works very well:
FILE *fd = popen("xterm", "r");
pclose(fd);
... will bring up a new xterm window, as expected.
Now I'm trying to achieve the same with posix_spawn(), which I understand to be possibly more resource-friendly, especially if we don't plan on communicating with the new child process:
/* p.we_wordv contains the argv, index 0 holds the actual command */
pid_t pid;
posix_spawnp(&pid, p.we_wordv[0], NULL, NULL, p.we_wordv, NULL);
... but this, for xterm as the command, yields the following on the parent's output:
xterm: Xt error: Can't open display:
xterm: DISPLAY is not set
Trying to launch other processes will yield other error messages, fail silently, or, in some cases like ls, work as expected. This makes it a bit hard for me to actually see a pattern yet.
Can you point out what is causing the second approach to behave differently than the first?

The message DISPLAY is not set tells you that xterm didn't find the DISPLAY environment variable. All graphical-output programs use this environment variable to connect to your screen.
It didn't find the variable because the environment was empty (it's the last NULL in your posix_spawnp function call). It seems that popen reuses the environment of current process, so it doesn't have this problem.
You might want to pass a manually-created environment, containing only the needed stuff, or just pass whatever environment your process has. The latter is more flexible (xterm will inherit various configuration settings from your process, which inherits them from your shell) but may be a security risk.
To access the environment of your process, use the environ global variable or change your main function to receive an additional parameter:
int main(int argc, char *argv[], char *envp[])
{
...
posix_spawnp(&pid, p.we_wordv[0], NULL, NULL, p.we_wordv, envp);
}

Related

Is there a system call to run systemctl in C program (not the system() function)?

I am on a Ubuntu 22.04 server. I want to run:
systemctl restart someService
but want to do so in a C program.
Intuitively I tried:
system("systemctl restart someService")
This did not work even if my program itself has setUid set to root as systemctl does not itself have setUid bit set to root.
I would like to write a program and set its uid to root so that anyone can execute it to restart a certain system service. This is only possible by using some direct function and not the system call as done above. Any suggestions?
I don't think there is a system-call that can do the job of systemctl in general. I think your approach of calling the systemctl command from your program is correct. But, I am not getting into the security considerations here. You should be really careful when writing set-uid programs.
Now, the main issue with your code is that system should not be used from set-uid binaries because it doesn't let you control the environment variables, which can be set maliciously before calling your program to change the behavior of the called process. Besides that, the system command calls /bin/sh to run your command which on some versions of Linux drop privilege as mentioned on the man-page linked above. The right approach would be to use execve family of functions that offer more control and do not spawn a shell. What you need to do can be done in the following way -
int main(int argc, char* argv[]) {
setuid(0);
setgid(0);
char *newargv[] = {"/usr/bin/systemctl", "restart", "someService", NULL};
char *newenviron[] = { NULL };
execve(newargv[0], newargv, newenviron);
perror("execve"); /* execve() returns only on error */
exit(EXIT_FAILURE);
}
Notice the empty (or pure) environment above. It is worth noting that the execve should not return unless there is an error. If you need to wait for the return value from the systemctl command, you might have to combine this with fork

Running cat /proc/cpuinfo in glib

I've been trying to look for questions on how to use g_spawn_sync() and they said that it is good to use when you want to execute a command in the terminal besides using pipes.
The only thing I can't figure out now is why the command cat /proc/cpuinfo doesn't work. error->message returns (No such file or directory)but if I use commands like ls or cat alone, it works. I also tried running cd /proc && cat cpuinfo but it gives me the same error.
I'm not an expert of glib but I read in the manual that I can use G_SPAWN_SEARCH_PATH so that it will check my PATH for the commands I can use without including the absolute path for the command.
I have the following code:
gchar *argv[] = { "cat /proc/cpuinfo", NULL };
char *output = NULL; // will contain command output
GError *error = NULL;
int exit_status = 0;
if (!g_spawn_sync(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
&output, NULL, &exit_status, &error))
{
printf("[getHardwareInfo] DEBUG: Error on g_spawn_sync %s.\n", error->message);
}
tl;dr: Do not use g_spawn_command_line_sync() unless you really know what you are doing.
Firstly, the actual problem you are hitting: John Szakmeister’s comment was correct: g_spawn_sync() takes an array of arguments, the first one of which is the path to the program to execute (or to look for in $PATH, if you’ve specified G_SPAWN_SEARCH_PATH). By passing the array { "cat /proc/cpuinfo", NULL }, you are saying that you want to run the program cat /proc/cpuinfo with no arguments, not the program cat with the argument /proc/cpuinfo.
However, there are many other problems here, and I think it’s important to mention them before people start cargo-culting this code, because they have security implications:
As LegalProgrammer says, why are you spawning cat when you could just call g_file_get_contents()?
Failing that, use GSubprocess instead of g_spawn_*(). It’s a more modern API, which allows you to monitor the lifecycle of the spawned process more easily, as well as getting streaming I/O in and out of the subprocess.
Do not ignore the warnings in the manual about the security implications of using g_spawn_command_line_sync(). There are several:
It will run the first matching program found in your $PATH, so if an attacker has control of your $PATH, or write access to any directory in that $PATH (such as ~/.local/bin), you will end up running an attacker-controlled program.
It’s a synchronous function, so will block on the subprocess completing, which could take unbounded time. Your program will be unresponsive for that time.
It returns the output in a single allocation, rather than as a stream, so if the subprocess returns many megabytes of output, you may hit allocation failures and abort.
The obvious next step from “g_spawn_command_line_sync() seems to do what I want” is “let’s use g_strdup_printf() to put together a command to run with it”, and then you have shell injection vulnerabilities, where an attacker who controls any of the parameters to that printf() can twist the entire shell command to execute their arbitrary code.
I'm answering my question here. After reading the manual again, I decided to use another function, g_spawn_command_line_sync, which is simpler to use than g_spawn_sync.
A simple version of g_spawn_sync() with little-used parameters removed, taking a command line instead of an argument vector. See g_spawn_sync() for full details. command_line will be parsed by g_shell_parse_argv(). Unlike g_spawn_sync(), the G_SPAWN_SEARCH_PATH flag is enabled. Note that G_SPAWN_SEARCH_PATH can have security implications, so consider using g_spawn_sync() directly if appropriate. Possible errors are those from g_spawn_sync() and those from g_shell_parse_argv().
Here is my new code:
char *output = NULL; // will contain command output
GError *error = NULL;
gint exit_status = 0;
if (!g_spawn_command_line_sync("cat /proc/cpuinfo", &output, NULL, &exit_status, &error))
{
printf("[getHardwareInfo] DEBUG: Error on g_spawn_command_line_sync %s.\n", error->message);

How to make c programe as daemon in ubuntu?

Hi I am new to the linux environment. I am trying to create daemon process.
#include<stdio.h>
int main()
{
int a=10,b=10,c;
c=sum(a,b);
printf("%d",c);
return (0);
}
int sum(int a,int b)
{
return a+b;
}
I want to create daemon process of it. May i know how can do this? Any help would be appreciated. Thank you.
A daemon generally doesn't use its standard input and output streams, so it is unclear how your program could be run as a daemon. And a daemon program usually don't have any terminal, so it cannot use clrscr. Read also the tty demystified page, and also daemon(7).
I recommend reading some good introduction to Linux programming, like the old freely downloadable ALP (or something newer). We can't explain all of it here, and you need to read an entire book. See also intro(2) and syscalls(2).
I also recommend reading more about OSes, e.g. the freely available Operating Systems: Three Easy Pieces textbook.
You could use the daemon(3) function in your C program to run it as a daemon (but then, you are likely to not have any input and output). You may want to log messages using syslog(3).
You might consider job control facilities of your shell. You could run your program in the background (e.g. type myprog myarg & in your interactive shell). You could use the batch command. However neither background processes nor batch jobs are technically daemons.
Perhaps you want to code some ONC-RPC or JSONRPC or Web API server and client. You'll find libraries for that. See also pipe(7), socket(7)
(take several days or several weeks to read much more)
First find what are the properties of daemon process, as of my knowledge a daemon process have these properties:
Should not have any parent (it itself should be parent)
Process itself is a session leader.
Environment change to root.
File mode creating mask should be zero.
No controlling terminal.
All terminal should be removed
Should not be un-mounted .
Implement the code by considering above properties which is
int i=0;
int main()
{
int pid;
pid=fork();
if(pid!=0) {
/** you can add your task here , whatever you want to run in background **/
exit(0);
}
else
{
setsid();//setting sessions
chdir("/");//root.. should'nt beunmounted
umask(0);
close(0);//all terminal are removed
close(1);
close(2);
while(1)
{
printf("i = %d \n",i);
i++;
}
}
return 0;
}
or you can go through man page of daemon()
int daemon(int nochdir, int noclose);
I hope it helps.
Instead of writing the code to make the C program a daemon I would go with an already mature tool like supervisor:
http://supervisord.org/
I think this below will work
screen cmd arg1 arg2
You can also try
nohup cmd arg1

How Do I Compile a C Program to Run Without a Command Box?

I need a very simple program to run on any version of Windows, let's say >= Win 98, without requiring any pre-installed framework like dotnet. I thought C would be a great idea to do this.
The program should start a process from the parent directory by using a system command.
Start C program (invisible) > program starts process > program exits
This is how it looks:
#include <stdio.h>
#include <stdlib.h>
int main() {
system("..\\someprogram.exe");
return 0;
}
I call this program from a Flash projector, which only allows to start programs in a specific subfolder "fscommand" – but I have to start a process located in the same directory as the projector.
Anyway, it works fine! But the C program opens a command box, then starts the process and leaves the command box open as long as the process runs. So here is how it should work, in order how i would appreciate it:
Do not open a command box at all (I'd like that, really ;)
Both 3) and 4)
Close the command box after starting the process (exit the C program)
Open the command box minimized by default
I can't change any Windows settings for the C executable or use a shortcut, as this will run directly from a CD later.
I use Open Watcom to compile my program. Both image types (target options) that produce an executable (Character-mode Executable / Windowed Executable) have the same result.
I did a google search and found http://www.ntwind.com/software/utilities/hstart.html
Your using a console app, you could change it to a windows app using winmain()
You can use a shortcut to a file in the same folder, not sure why your discounting that method.
start will give you a fork so your intermediate app can close - not sure about win98 tho.
system("start ..\\someprogram.exe");
Instead of system you can use createProcess to launch the app, theis will avoid the system commands console.
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( "..\\someprogram.exe", // module name
NULL, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return;
}
// Wait until child process exits. In your case you don't care to wait anyway
// WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
The console window shows up because you built your program as a console application. I don't know how to avoid that in C, but in Delphi is was a simple {$Console Off} pragma in the project file.
GCC has a command line option -mwindows, which I think achieves the same, so you could search into this direction.
I think the _exec and/or _spawn functions do what you need, though I'm not sure.
If not, you can always use CreateProcess, though it can be a little more tedious in some ways.
You could (for example) use hstart instead of your own program to start that exe.
(This would result in no black box at all.)
CreateProcess with CREATE_NO_WINDOW flag is what you want, but I want to add something. To support also cmd style commands (such as DIR, SET, ... ) which have no executables and can't be passed to CreateProcess alone, you should call cmd.exe /C someprogram where someprogram is name of executable, bat file, or command.
A friend came up with a completely different solution. Now I use AutoIt with a short compiled script to start the process. This is very simple and the launcher process is completely invisible. :)
filename = ..\someprogram.exe
if FileExist(filename) {
Run, open %filename%
}

Start a process in the background in Linux with C

I am trying to do something a little weird here. I need to start a process, logcat, from a deamon that will run in the background and print to the terminal without taking control of stdin. It is for logging so ideally logcat will print log messages while still allowing the user to input standard commands and initialize programs from the shell. Here is the code for the daemon I have so far. The program, logcat, starts and shows log messages but I cannot enter any commands into stdin as it appears that the program has taken control of stdin.
int main ( int argc, char** argv, char** env )
{
int fd;
if ((fd = open("/dev/console", O_RDWR)) < 0) {
fd = open("/dev/null", O_RDWR);
}
printf("THIS IS A TEST\n");
dup2(1, fd);
dup2(2, fd);
pid_t childpid = fork();
if(childpid == -1) {
perror("Failed to fork, logcat not starting");
return 1;
}
if(childpid == 0) {
//this is the child, exec logcat
setsid();
int execReturn = execl("/system/bin/logcat", "logcat", (char *) 0);
} else {
//this is the parent do nothing
close(fd);
return 0;
}
close(fd);
return 0;
}
Thanks
The 'logcat' command seems to be for Android development - that might explain the odd location of the command.
The key operation that you must fix is to ensure that you close your current standard input (the terminal) and open /dev/null/ for the input device:
close(0);
if ((fd = open("/dev/null", O_RDONLY)) != 0)
...error - failed to open /dev/null!
This means that your daemonized child process will not read anything from the terminal.
What I think you want to do is:
Run your launcher program from a command line, which will have standard input, standard output and standard error connected to 'the terminal'.
Inside your program, you want to replace the standard input so it comes from /dev/null.
You want to leave standard output alone - you want logcat to write to the current standard output.
You probably want to leave standard error alone too.
At some point in the proceedings, you do your daemonization properly (borrowing the link from #bstpierre's answer), making sure that the terminal you are connected to is not your controlling terminal, so that interrupts and hangups sent to the terminal don't affect your daemon. The plumbing is simpler than what you have set up - you should deal with standard input and leave standard output and standard error unchanged (instead of changing the outputs and leaving the input unchanged).
Now, you might want the output to go to /dev/console; if so, then it is reasonable to revise the code to open /dev/console. However, it is not reasonable to fall back on /dev/null if you can't open /dev/console; your program should report an error and fail (because there is no point in having logcat writing to /dev/null!). Make sure you open the console with the O_NOCTTY flag so it does not become the controlling terminal for the daemon.
The final comment I'd make is:
Are you sure you want random text appearing over your terminal or console when it is in use for other things?
I don't much like it when that happens.
See also: SO 958249
How to Daemonize in Linux [dead link]
How to Daemonize in Linux [wayback machine archive of the above]
gist on github -- code taken from link above
Executive summary:
One of the things I keep running across is Linux daemons that don’t properly daemonize themselves. To properly daemonize, the following steps must be followed.
The fork() call is used to create a separate process.
The setsid() call is used to detach the process from the parent (normally a shell).
The file mask should be reset.
The current directory should be changed to something benign.
The standard files (stdin,stdout and stderr) need to be reopened.
Failure to do any of these steps will lead to a daemon process that can misbehave. The typical symptoms are as follows.
Starting the daemon and then logging out will cause the terminal to hang. This is particularly nasty with ssh.
The directory from which the daemon was launched remains locked.
Spurious output appears in the shell from which the daemon was started.
There is special purposed function for this in glibc:
#include <unistd.h>
...
/* We are in the parent, yet */
daemon(0,0);
/* Now we are in the child */
...
More details here http://linux.die.net/man/3/daemon

Resources