Execute a shell command in C but not through web page - c

I have a program in C/java/html 5
The service file of the program runs as root user and it is on an Archlinux distribution.
I want to have the result IP address that SMB will find and show it in an html page i have.
The part of the code i am interested is this:
sds ns_server_list(sds buffer, sds method, int request_id)
{
FILE *fp = popen("/usr/bin/nmblookup -S \'*\' | grep \"<00>\" | awk \'{print $1}\'", "r");
// returns three lines per server found - 1st line ip address 2nd line name 3rd line workgroup
if (fp == NULL)
{
LOG_ERROR("Failed to get server list");
buffer = jsonrpc_respond_message(buffer, method, request_id, "Failed to get server list", true);
}
If i run the program through shell (./test) and after compile, it returns the results in HTML just fine.
If i run it through the web interface of program and through a service file, it returns these SMB errors in journalctl -xe:
WARNING: no network interfaces found
name_query failed to find name *
ERROR Executing syscmd "/usr/bin/nmblookup -S '*'" failed
SMB.conf
[global]
server string = SMB Server
security = user
guest account = root
map to guest = bad user
log level = 0
load printers = No
syslog = 0
directory mask = 0775
create mask = 0775
browseable = yes
#veto files = /._*/.DS_Store/
interfaces = eth0 192.168.2.0/24
Summarized...
If i run the program through service file and without IP address in SMB.conf i have the errors in journalctl. If i put the IP everything is ok but i do not want to work it like this way (dynamic ip and eth0 do not work, same errors).
If i run the program through shell with the executable compiled file (./test) everything play fine without ip address in smb.conf
Why is that?
Thank you.

Related

How to export the tcpdump result running in real-time on a remote machine into a pcap file on my computer?

I have a Wi-Fi probe which I would manage. In a thread, I have to run a tcpdump by SSH and to get result through the ssh tunnel and write it into a pcap file on my own computer.
Now, I run the tcpdump command and I get back the result but I don't know how to write it into a PCAP file and I don't really what is the type of data that I get back.
self.dataSSH=self.TunnelSSH_data.OuvrirTunnelSSH() #self.dataSSH is a paramiko.SSHClient object
sin, sout, serr = self.dataSSH.exec_command(self.ssh_command, get_pty=True)
while self.running :
for l in self.line_buffered(sout):
print(l)
def line_buffered(self,f):
line_buf = ""
while not f.channel.exit_status_ready():
line_buf += to_unicode(f.read(1))
if line_buf.endswith('\n'):
yield line_buf
line_buf = ''
The content of ssh_command is :
"tcpdump -i " + <Interface to monitor> + " -B 8192 -s 500 -U -n -w -"
Today, I just print the results in unicode but I don't know how to write it in pcap file.
I would have to see the code that calls "tcpdump" to give you a clear answer, but you should know that "tcpdump" already gives you the option to write the results into a ".pcap" file. Example:
tcpdump -s 0 port ftp or ssh -i eth0 -w mycap.pcap
The code above dumps the results into "mycap.pcap" (taken from https://linuxexplore.com/2012/06/07/use-tcpdump-to-capture-in-a-pcap-file-wireshark-dump/ ).
So what I would try is generating the pcap in the probe, then transfer the pcap trace to your computer, and then removing the pcap file off the probe's disk if that's really needed.

Cgi programming in C, calling system() from my cgi program.

I've had a CGI program that I wrote in C and have used for some 20 years, and for the first time in a long time, I'm running in Windows, specifically windows 10, and I can't get a system() call to execute from the CGI program. It seems like the system call is just ignored and doesn't create my output on the server side that I expect.
The CGI program is called from a form and using sprintf makes up the html page response into a giant buffer (szbuffer) and then prints to stdout which in the apache world goes back to the client. Here is the routine that outputs the built up html page to the user:
/** Print the CGI response header, required for all HTML output. **/
/** Note the extra \n, to send the blank line. **/
printf("Content-type: text/html\n\n") ;
printf("%s\n<!--JL 7/12/01 11:00am -->\n",szBuffer);
free ( szBuffer);
Now this has worked fine for years, but in this version I wanted to run some system calls to search a csv file and create an answer set to be read with an fopen(). The way I've done this in linux is to just run commands using the system() command:
getvaluecgivar(szcustomer_chain, "cust_field3", globals);
getvaluecgivar(szcustomer_id, "cust_field4", globals);
//sprintf(szdoscommand,"./awklookup_customer_id.bat %s %s "
sprintf(szdoscommand,"awklookup_customer_id.bat %s %s"
,szcustomer_chain
,szcustomer_id
);
system(szdoscommand);
system("cat lunch.trace >hw.lis");
system("cat lunch.trace >/temp/hwt.lis");
sprintf(szTempstring,"system command:%s: return code=%d\n"
,szdoscommand
,return_from_system_call
);
strcat(szBuffer, szTempstring);
} // then lookup by customer id
for reasons I need explaining and fixing, it appears as if the system() call (all three of them) never execute. The two "cat lunch.trace" system calls were just a test to see if I could get ANY system call to run and those commands also seem to fail. Now I know I've done this on Linux without any issue before:
FILE * tfile;
system( "cat /tmp/relaystatus20*.txt >/tmp/rs20all.txt");
tfile = fopen( "/tmp/rs20all.txt" , "r");
if (tfile) {
strcat(szBuffer, "<pre>");
while(!feof(tfile)) {
and this creates the file rs20all.txt in the /tmp directory.
Is there something special I have to do on Windows? I did capture the return code from the awklookup_customer_id.bat and it was 127.
Here is awklookup_customer_id.bat, it runs fine from either the dos prompt cmd.exe or a cygwin64 terminal:
call \jon\bat\local >t.lis
rem echo %1%, %2%
set arg1=%1%
set arg2=%2%
gawk -F',' '{ if($3==%arg1%) print $0 }' t5_clean_customer.csv >awk01.lis
gawk -F',' '{ if($4==%arg2%) print $0 }' awk01.lis >awk02.lis
\jon\bat\grep.exe -nf awk02.lis t5_clean_customer.csv >awk03.lis
cat awk03.lis|wc -l >awk03_c.lis
set LINE_COUNT=0
set /p LINE_COUNT=<awk03_c.lis
cut -d: -f1 awk03.lis >awk03_ln.lis
set LINE_NUMBER=0
set /p LINE_NUMBER=<awk03_ln.lis
SET /A Result = %LINE_COUNT% * 10000000 + %LINE_NUMBER%
echo number of lines that match :%LINE_COUNT% line number: %LINE_NUMBER%
rem pause
exit %Result%
I'm running Apache 2.4, here are the environment variables that the cgi program gets:
Print_environ::
[HTTP_HOST=localhost]
[HTTP_CONNECTION=keep-alive]
[CONTENT_LENGTH=380]
[HTTP_CACHE_CONTROL=max-age=0]
[HTTP_ORIGIN=http://localhost]
[HTTP_UPGRADE_INSECURE_REQUESTS=1]
[CONTENT_TYPE=application/x-www-form-urlencoded]
[HTTP_USER_AGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36]
[HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8]
[HTTP_REFERER=http://localhost/cgi-bin/bf_customer.cgi]
[HTTP_ACCEPT_ENCODING=gzip, deflate, br]
[HTTP_ACCEPT_LANGUAGE=en-US,en;q=0.9]
[PATH=/cygdrive/c/Program Files (x86)/Common Files/Oracle/Java/javapath:/cygdrive/c/Program Files (x86)/Intel/iCLS Client:/cygdrive/c/Program Files/Intel/iCLS Client:/cygdrive/c/Windows/system32:/cygdrive/c/Windows:/cygdrive/c/Windows/System32/Wbem:/cygdrive/c/Windows/System32/WindowsPowerShell/v1.0:/cygdrive/c/Program Files (x86)/Intel/Intel(R) Management Engine Components/DAL:/cygdrive/c/Program Files/Intel/Intel(R) Management Engine Components/DAL:/cygdrive/c/Program Files (x86)/Intel/Intel(R) Management Engine Components/IPT:/cygdrive/c/Program Files/Intel/Intel(R) Management Engine Components/IPT:/cygdrive/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/cygdrive/c/Windows/system32/config/systemprofile/.dnx/bin:/cygdrive/c/Program Files/Microsoft DNX/Dnvm:/cygdrive/c/Program Files (x86)/Windows Kits/8.1/Windows Performance Toolkit:/cygdrive/c/Program Files/Intel/WiFi/bin:/cygdrive/c/Program Files/Common Files/Intel/WirelessCommon:/cygdrive/c/Program Files (x86)/2Printer:/cygdrive/c/Program Files/MATLAB/MATLAB Runtime/v93/runtime/win64:/cygdrive/c/Program Files (x86)/Pico Technology/PicoScope6:/cygdrive/c/Program Files (x86)/IVI Foundation/VISA/WinNT/Bin:/cygdrive/c/Program Files/IVI Foundation/VISA/Win64/Bin:/cygdrive/c/Users/jleslie/AppData/Local/Microsoft/WindowsApps]
[SYSTEMROOT=C:\Windows]
[COMSPEC=C:\Windows\system32\cmd.exe]
[PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC]
[WINDIR=C:\Windows]
[SERVER_SIGNATURE=]
[SERVER_SOFTWARE=Apache/2.4.23 (Win64)]
[SERVER_NAME=localhost]
[SERVER_ADDR=::1]
[SERVER_PORT=80]
[REMOTE_ADDR=::1]
[DOCUMENT_ROOT=C:/jon/programs/Apache24/htdocs]
[REQUEST_SCHEME=http]
[CONTEXT_PREFIX=/cgi-bin/]
[CONTEXT_DOCUMENT_ROOT=c:/jon/programs/Apache24/cgi-bin/]
[SERVER_ADMIN=admin#example.com]
[SCRIPT_FILENAME=C:/jon/programs/Apache24/cgi-bin/bf_customer.cgi]
[REMOTE_PORT=52945]
[GATEWAY_INTERFACE=CGI/1.1]
[SERVER_PROTOCOL=HTTP/1.1]
[REQUEST_METHOD=POST]
[QUERY_STRING=]
[REQUEST_URI=/cgi-bin/bf_customer.cgi]
[SCRIPT_NAME=/cgi-bin/bf_customer.cgi]
[TERM=cygwin]
[HOME=/home/jleslie]
cgi vars:
[colora] = [maroon]
[cust_field1] = []
[cust_field2] = []
[cust_field3] = [0]
[cust_field4] = [16]
I figured it out. the answer has to do with httpd.conf. I needed to tell apache that its ok to run .bat file:
# (You will also need to add "ExecCGI" to the "Options" directive.)
#
#AddHandler cgi-script .cgi
AddHandler cgi-script .bat # add .exe if you wish
Options +ExecCGI +FollowSymlinks
sorry about the confusion with the return_from_system_call, I was adding and removing it so often I posted a version of the code where it wasn't set. This is the final code section that works:
getvaluecgivar(szcustomer_chain, "cust_field3", globals);
getvaluecgivar(szcustomer_id, "cust_field4", globals);
sprintf(szdoscommand,"awklookup_customer_id.bat %s %s"
,szcustomer_chain
,szcustomer_id
);
return_from_system_call =system(szdoscommand);
sprintf(szTempstring,"system command:%s: return code=%d\n"
,szdoscommand
,return_from_system_call
);
strcat(szBuffer, szTempstring);

hiredis getting err 1 REDIS_ERR_IO No such file or directory

redisAsyncConnectUnix() returns a redisAsyncContext(not NULL) that has err=1 i.e REDIS_ERR_IO with errstr "No such file or directory" , what file/directory are they looking for ?
Redis is up and running, was able to SET from redis-cli
redisAsyncConnectUnix is used to connect to the server using a Unix Domain Socket, which is materialized by a pseudo-file. The path of this file has to be provided as a parameter:
redisAsyncContext *redisAsyncConnectUnix(const char *path);
For instance, you could use:
path = /tmp/redis.socket
However, you need to check that the server (which has to run on the same machine than the client), is listening to the same path. Check the definition of the following parameters in the Redis configuration file:
unixsocket /tmp/redis.socket
unixsocketperm 755
Make sure the path is valid, and access rights are correct. You can check that the configuration is ok on server-side by running:
redis-cli -s /tmp/redis.socket

How to handle SSH failures in Expect script

I have an expect script that logs in to a list of devices and run a series of commands.
Everything works fine except when one of the hosts is/becomes unreachable and the script just exits. Is there a way to get it to skip the unreachable host & move on to the remaining devices?
Here's the main body of my script.
foreach host $hosts {
spawn -noecho /usr/bin/ssh user#$host
set timeout 10
expect {
"assword:" { send [string trimright "$pwd" "\r"] }
"No route*" {puts "Host error -> $expect_out(buffer)";exit}
"Could not resolve*" {puts "Host error -> $expect_out(buffer)";exit}
}
expect "#"
send "term len 0\r"
expect "#"
send "show version\r"
expect "#"
send "exit\r"
expect eof
}
And here's what i get:
.
. <output of reachable device - R1>
.
Connection to R1 closed by remote host.
Connection to R1 closed.
ssh: Could not resolve hostname R2: Name or service not known
Host error -> ssh: Could not resolve hostname R1: Name or service not known
Given that Expect is, essentially, an extension to the TCL language, your question really boils down to "how to I end a loop iteration early in TCL?".
The answer is, use the continue command instead of the exit command.

How to detect a user logged in through GUI in Linux

I would like to capture the user name logged in through GUI in my program. My program is running as a daemon from root login. If a non root user logs in through GUI my program should be notified.
I am pasting my current program which calls a perl script making use of system call to check who is the current user logged in. I am pasting my perl script too for reference.
#include <X11/Xlib.h>
#include <X11/Xos.h>
#include <X11/Xfuncs.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
int main()
{
char *user;
char buf[1024];
int fd, ret;
fd = open("/tmp/log", O_TRUNC|O_RDWR|O_CREAT);
if (!fd) {
printf("Error opening file\n");
exit(1);
}
chmod("/tmp/log", S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP
| S_IROTH | S_IWOTH | S_IXOTH);
daemon(0, 0);
while (1) {
system("perl /home/curr-usr.pl");
sleep(5);
}
return 0;
}
The perl script which is used to get the current user logged in.
#!/usr/bin/perl
my $result;
$result = `whoami`;
open FH, "+>>", "/tmp/log" or die $!;
print FH "$result ";
close (FH);
In the c program above I am calling the perl script in a while loop every 5 seconds. The perl script makes use of the command "whoami" to get the current user logged in & dumps it into the /tmp/log file.
What I want to achieve is if user1 logs in the perl script should give me the current user to be user1. Instead the perl script gives me root as the current user irrespective of the user I am logged in through GUI as I am running the C program & perl script with root user.
Could anyone please advise me with a mechanism by which the C program could get to know the current user logged in through GUI ?
Any help is greatly appreciated.
You can detect the user using the main display like this:
#!/bin/bash
#Detect the name of the display in use
display=":$(ls /tmp/.X11-unix/* | sed 's#/tmp/.X11-unix/X##' | head -n 1)"
#Detect the user using such display
user=$(who | grep '('$display')' | awk '{print $1}')
#Detect the id of the user
uid=$(id -u $user)
I am using XFCE4 and LXDM. "who" and "users" report only users that are logged on a terminal. GUI logon is not reported as Nominal Animal pointed out (Thanks!). I use "pgrep xfce" to check if XFCE4 is running. Following prints out current xfce-user:
#!/usr/bin/perl
# Get all processes
my #xfce_processes = `pgrep xfce`;
# If processes exist, get user of first process in list.
if(scalar #xfce_processes) {
print `ps -o user h $xfce_processes[0]`;
}
else
{
# No xfce processes.
;
}
As you mentioned your program runs as a daemon. Consequently any process it spawns would be run as the same user as one that started that daemon. The user that logs in via UI (or any other method) would never be the user you can get by calling whoami from your daemon.
Instead what you should do is explicitly notify your daemon of a login event or, if that is not an option, keep a list of all the logged-in sessions currently running on the box and see if new sessions appear - that would be a session of a newly logged-in user.
The programms who and users get their information from the file /var/run/utmp.
The file contains N entries of the size of "struct utmp", defined in <utmp.h>
You are interested in the USER_PROCESS type entries. The host field contains the display.
Note that there are multiple entries for the same display if the user opened some terminal emulations (xterm, konsole...).
You could monitor this file or /var/log/wtmp for a history
struct utmp ut_entry;
FILE *fp = fopen(UTMP_FILE, "r");
if( !fp )
{
printf("Could not open utmp file!");
return;
}
while(fread(&ut_entry, sizeof(struct utmp), 1, fp) == 1)
{
if(ut_entry.ut_type != USER_PROCESS)
continue;
// string entries are not 0 terminated if too long...
// copy user name to make sure it is 0 terminated
char tmpUser[UT_NAMESIZE+1] = {0};
strncpy(tmpUser, ut_entry.ut_user, UT_NAMESIZE);
// do more stuff... read the display from ut_entry.host
}
For more information see the utmp manual page
You probably want to investigate either ConsoleKit or its newer incarnation loginctl.
These tools are specifically designed for managing seats and sessions, while maintaining distinction between local text console, GUI and remote sessions. They are not guaranteed to be present on every X11 machine, but if yours is relatively recent, chances are it uses either one or the other tool.
For anyone else coming here for xfce4, what I had to do was run ps -aux | grep xfce4 then there was a line:
root 2497 0.0 0.3 323052 13408 ? Sl 01:24 0:00 xfce4-session
I run kill -9 2497 and that got rid of it. For me this was a hung instance I wanted to kill from SSH.

Resources