How to detect a user logged in through GUI in Linux - c

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.

Related

Execute a shell command in C but not through web page

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.

Execute commands as root without root password or sudo

I understand the implications of running a script as root, especially by a web application. However as part of my web application, I need to use curl with tor and this needs resetting the tor ip occasionally. tor can get a new ip when the service is restarted with service tor restart. Since only root can do that, I've written a C wrapper script to do what I need, and compiled it and set setuid root on it, and changed to root user ownership. However, it still asks me root password when it's run as an unprivileged user. As root, a service restart shouldn't ask password.
My script:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
void ExecAsRoot (char* str);
int main ()
{
setuid (0);
setvbuf(stdout, NULL, _IONBF, 0);
printf ("Host real ip is: ");
ExecAsRoot("ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d'/'");
ExecAsRoot("/usr/sbin/service tor restart");
// sleep(2);
printf ("Tor should have switched to a new ip by now.\nNew ip is: ");
ExecAsRoot("torify curl ifconfig.co 2>/dev/null");
return 0;
}
void ExecAsRoot (char* str) {
system (str);
}
I've done the following:
chown root restartor
chmod u=rwx,go=xr restartor
Output:
Host real ip is: 7.17.11.23
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ===
Authentication is required to restart 'tor.service'.
Authenticating as: root
Password:
How can I get this to run as web user without supplying root password?
You didn't set the setuid bit in the file permissions:
#-------v
chmod u=srwx,go=xr restartor

Flow Control and Return Values in a BashScript

I'm quite new to bash scripting and i've been working on a small bash file that can do a few things for me. First of all, i'm calling this from a C function using system() and i'd like the script to return a value (1 for error, 0 for OK). Is this possible?
int kinit() {
int err = system("/home/bluemoon/Desktop/GSSExample/kinitScript.sh");
}
Second, using Zenity, i managed to create a pop up window to insert user/password. Now, according to what the user does, multiple things should happen. If he closes the window or clicks "cancel", nothing should happen. If he clicks "OK", then i should check the input (for empty text boxes or something).
Assuming a correct input, i will use Expect to run a kinit program (it's a promt related with Kerberos) and log in. Now, if the password is correct, the prompt closes and the script should return 0. If it's not, the prompt will show something like "Kinit: user not found". I wanted to, in any case of error (closing window, clicking cancel or wrong credentials) return 1 in my script and return 0 on success.
#!/bin/bash
noText=""
ENTRY=`zenity --password --username`
case $? in
0)
USER=`echo $ENTRY | cut -d'|' -f1`
PW=`echo $ENTRY | cut -d'|' -f2`
if [ "$USER"!="$noText" -a "$PW"!="$noText" ]
then
/usr/bin/expect -c 'spawn kinit '`echo $USER`'; expect "Password for '`echo $USER`':" { send "'`echo $PW`'\r" }; interact'
fi
;;
1)
echo "Stop login.";;
-1)
echo "An unexpected error has occurred.";;
esac
My if isn't working properly, the expect command is always run. Cancelling or closing the Zenity window also always lead to case "0". I've also tried to return a variable but it says i can only return vars from inside functions?
Well, if anyone could give me some pointers, i'd appreciate it.
Dave
i'd like the script to return a value
Sure, just use exit in appropriate places
exit: exit [n]
Exit the shell.
Exits the shell with a status of N. If N is omitted, the exit status
is that of the last command executed.
My if isn't working properly, the expect command is always run.
if [ "$USER" != "$noText" -a "$PW" != "$noText" ]
# ^ ^ ^ ^
# | | | |
# \----- notice spaces ----/

get physical hdd's list in c

People, I need get the list of hard disk connected in C language on Linux system:
Example, running a program on a computer with 2 IDE disks and 1 SATA disk connected.
./a.out
Out required:
/dev/hda
/dev/hdb
/dev/sda
help?
Use libsysfs, the recommended way to query the kernel about attached devices of all kinds.
FILE *fp = popen("fdisk -l | grep \"Disk /\" | awk '{print $2};' | sed 's/://'", "r");
while(fgets(path, sizeof(path) -1,fp) != NULL)
//your code
pclose(fp);
The simplest way would be simply read and parse /proc/partitions.
Maybe you can reference fdisk's source code.
Follow this website:
ftp://ftp.gnu.org/gnu/fdisk
Command Line
"ls /sys/block/"
will return output as:
sda sdb sdc
From there, you could creat a script that pipes it to a file, then read in that file as an array or linked list to manipulate the data however you see fit (such as adding /dev/ in front of all device names in the list).

How do I give write permission to file in Linux?

How can I (programmatically) give write permission on a file to a particular user in Linux? Like, for example, its owner? Everyone has read access to this file.
In a shell or shell script simply use:
chmod u+w <filename>
This only modifies the write bit for the user, all other flags remain untouched.
If you want to do it in a C program, you need to use:
int chmod(const char *path, mode_t mode);
First query the existing mode via
int stat(const char *path, struct stat *buf);
... and just set the write bit by doing newMode = oldMode | S_IWUSR. See man 2 chmod and man 2 stat for details.
The octal mode 644 will give the owner read and write permissions, and just read permissions for the rest of the group, as well as other users.
read = 4
write = 2
execute = 1
owner = read | write = 6
group = read = 4
other = read = 4
The basic syntax of the command to set the mode is
chmod 644 [file name]
In C, that would be
#include <sys/stat.h>
chmod("[file name]", 0644);
chmod 644 FILENAME
6 is read and write, 4 is read only. Assuming the owner of the file is the user you wish to grant write access to.
You can do that using chmod, on ubuntu you can try out
$sudo chmod 666
This would give read/write permissions to all...check this out for more details:
http://catcode.com/teachmod/
You can use chmod 777 <filename>

Resources