Bring back e_sys just for mount, unmount and eject

This reverts commit a43869cdc0.

I still need this for efm... i forgot... :( So bring back the bits we
need until it's no longer needed...
This commit is contained in:
Carsten Haitzler 2020-01-16 23:05:02 +00:00
parent 5ce778194d
commit 5cc02d6467
5 changed files with 1004 additions and 0 deletions

View File

@ -1,3 +1,26 @@
MOUNT = '/bin/mount'
UMOUNT = '/bin/umount'
EJECT = '/usr/bin/eject'
if host_machine.system().contains('bsd') == true
MOUNT = '/sbin/mount'
UMOUNT = '/sbin/umount'
EJECT = '/usr/sbin/cdcontrol eject'
endif
sysactions = configuration_data()
sysactions.set('MOUNT' , MOUNT)
sysactions.set('UMOUNT' , UMOUNT)
sysactions.set('EJECT' , EJECT)
if get_option('install-sysactions')
configure_file(input : 'sysactions.conf.in',
output : 'sysactions.conf',
install_dir : join_paths(dir_sysconf, 'enlightenment'),
configuration: sysactions
)
endif
if get_option('install-enlightenment-menu')
install_data('e-applications.menu',
install_dir: join_paths(dir_sysconf, 'xdg/menus')

View File

@ -0,0 +1,77 @@
# ENLIGHTENMENT SYSTEM ACTIONS CONFIGURATION
#
# This is a system configuration for allowing or denying certain users or
# groups to be able to do certain actions that involve system restricted
# actions such as halt, reboot, suspend, hibernate etc.
#
# This file is read in order from top to bottom - the first rule to MATCH
# will be used for a user or a group, and nothing after that is read.
#
# You must put all the ACTION definitons BEFORE user and group rule matches.
# Any action definitons after a rule match has been found will be ignored.
# This allows actions to be re-defined for different user groups, so matches
# so the command for an action can change for matches to the rules later on.
#
# Any user or group NOT matched by an allow or a deny will be ALLOWED to
# perform the action by default (system administrators should be aware of
# this and implement whatever policies they see fit). Generally speaking
# a user of a workstation, desktop or laptop is intended to have such abilities
# to perform these actions, thus the default of allow. For multi-user systems
# the system administrator is considered capable enough to restrict what they
# see they need to.
#
# A WARNING to admins: do NOT allow access for users to this system remotely
# UNLESS you fully trust them or you have locked down permissions to halt/reboot
# suspend etc. here first. You have been warned.
#
# FORMAT:
#
# action: nam command to run
#
# user: username allow: halt reboot suspend hibernate
# group: groupname deny: *
# group: * deny: *
# user: * allow: suspend
# user: billy allow: halt reboot
# group: staff deny: halt suspend hibernate
#
# etc.
#
# user and group name can use glob matches (* == all for example) like the
# shell. as can action names allowed or denied.
action: /bin/mount @MOUNT@
action: /bin/umount @UMOUNT@
action: /usr/bin/eject @EJECT@
# root is allowed to do anything - but it needs to be here explicitly anyway
user: root allow: *
# members of operator, staff and admin groups should be able to do all
group: operator allow: *
group: staff allow: *
group: admin allow: *
group: sys allow: *
group: wheel allow: *
group: adm allow: *
# common "user" groups for "console users" on desktops/laptops
group: dialout allow: *
group: disk allow: *
group: adm allow: *
group: cdrom allow: *
group: floppy allow: *
group: audio allow: *
group: dip allow: *
group: plugdev allow: *
group: netdev allow: *
group: bluetooth allow: *
group: video allow: *
group: voice allow: *
group: fax allow: *
group: tty allow: *
# put in a list of other users and groups here that are allowed or denied etc.
# e.g.
# user: myuser allow: *
# user: another allow: suspend hibernate
#
# deny everyone else by default
user: * deny: *

182
src/bin/e_sys_l2ping.c Normal file
View File

@ -0,0 +1,182 @@
#include "config.h"
#include <Ecore.h>
#ifdef HAVE_BLUETOOTH
#include <unistd.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
#include <sys/select.h>
#include <fcntl.h>
#endif
#define MAX_SZ 500
double
e_sys_l2ping(const char *bluetooth_mac, int timeout_ms)
{
#ifdef HAVE_BLUETOOTH
char send_buf[L2CAP_CMD_HDR_SIZE + MAX_SZ];
char recv_buf[L2CAP_CMD_HDR_SIZE + MAX_SZ];
char tmp[18];
bdaddr_t bdaddr;
l2cap_cmd_hdr *send_cmd;
l2cap_cmd_hdr *recv_cmd;
struct sockaddr_l2 addr;
socklen_t optlen;
double start;
int fd, err, size, i;
fd_set rfds, wfds, exfds;
struct timeval tv;
// Create socket
fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_NONBLOCK, BTPROTO_L2CAP);
if (fd < 0)
{
perror("Can't create socket");
return -1;
}
// Bind to local address
memset(&addr, 0, sizeof(addr));
addr.l2_family = AF_BLUETOOTH;
bacpy(&bdaddr, BDADDR_ANY);
bacpy(&addr.l2_bdaddr, &bdaddr);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("Can't bind socket");
close(fd);
return -1;
}
if (fcntl(fd, F_SETFL, O_NONBLOCK) != 0)
{
perror("Can't set socket to non-blocking... continue");
}
// Connect to remote device
memset(&addr, 0, sizeof(addr));
addr.l2_family = AF_BLUETOOTH;
str2ba(bluetooth_mac, &addr.l2_bdaddr);
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
{
perror("Can't bind connect socket");
close(fd);
return -1;
}
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_ZERO(&exfds);
FD_SET(fd, &wfds);
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
start = ecore_time_get();
err = select(fd + 1, &rfds, &wfds, &exfds, &tv);
if (err == 0)
{
fprintf(stderr, "Connect timeout %s\n", bluetooth_mac);
return -1;
}
// adjust timeout by how long we waited to connect
timeout_ms -= (ecore_time_get() - start) * 1000;
if (timeout_ms < 1) timeout_ms = 1;
// Get local address
memset(&addr, 0, sizeof(addr));
optlen = sizeof(addr);
if (getsockname(fd, (struct sockaddr *)&addr, &optlen) < 0)
{
perror("Can't get local address");
return -1;
}
ba2str(&addr.l2_bdaddr, tmp);
size = 44; // use std 44 byte ping size, but no more than MAX_SZ
send_cmd = (l2cap_cmd_hdr *)send_buf;
send_cmd->ident = 200;
send_cmd->len = htobs(size);
send_cmd->code = L2CAP_ECHO_REQ;
// init buffer with some content
for (i = 0; i < size; i++)
{
// ABCDEF....WXYZABCEF... up to "size" chars
send_buf[L2CAP_CMD_HDR_SIZE + i] = 'A' + (i % 26);
}
// get our time just before a send
start = ecore_time_get();
// send the ping
if (send(fd, send_buf, L2CAP_CMD_HDR_SIZE + size, 0) <= 0)
{
perror("Send failed");
return -1;
}
do
{
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_ZERO(&exfds);
FD_SET(fd, &rfds);
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
err = select(fd + 1, &rfds, &wfds, &exfds, &tv);
if (err < 0)
{
perror("Select failed");
return -1;
}
else if (err == 0)
{
fprintf(stderr, "Select timeout %s\n", bluetooth_mac);
return -1;
}
err = recv(fd, recv_buf, L2CAP_CMD_HDR_SIZE + size, 0);
if (err == 0)
{
fprintf(stderr, "Disconnect %s\n", bluetooth_mac);
return -1;
}
else if (err < 0)
{
perror("Recv failed");
return -1;
}
recv_cmd = (l2cap_cmd_hdr *)recv_buf;
recv_cmd->len = btohs(recv_cmd->len);
// we only want the 200 ident response packets
if (recv_cmd->ident != 200) continue;
if (recv_cmd->code == L2CAP_COMMAND_REJ)
{
fprintf(stderr, "Peer %s doesn't do echo\n", bluetooth_mac);
return -1;
}
if (recv_cmd->len != size)
{
fprintf(stderr, "Size %i echo for %s does not match %i\n",
recv_cmd->len, bluetooth_mac, size);
return -1;
}
if (memcmp(send_buf + L2CAP_CMD_HDR_SIZE,
recv_buf + L2CAP_CMD_HDR_SIZE, size) != 0)
{
fprintf(stderr, "Echo response for %s data does not match sent data\n", bluetooth_mac);
return -1;
}
fprintf(stderr, "Device %s responded\n", bluetooth_mac);
break;
}
while (1);
close(fd);
// time it took to send and get our response
return ecore_time_get() - start;
#else
(void) bluetooth_mac;
fprintf(stderr, "e_sys_l2ping nop mac=%s timeout=%ims\n", bluetooth_mac, timeout_ms);
return -1;
#endif
}

711
src/bin/e_sys_main.c Normal file
View File

@ -0,0 +1,711 @@
#include "config.h"
#define __USE_MISC
#define _SVID_SOURCE
#define _DEFAULT_SOURCE
#ifdef HAVE_FEATURES_H
# include <features.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_ENVIRON
# define _GNU_SOURCE 1
#endif
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <pwd.h>
#include <grp.h>
#include <fnmatch.h>
#include <ctype.h>
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
#include <Eina.h>
#ifdef HAVE_ENVIRON
extern char **environ;
#endif
/* local subsystem functions */
#ifdef HAVE_EEZE_MOUNT
static Eina_Bool mountopts_check(const char *opts);
static Eina_Bool mount_args_check(int argc, char **argv, const char *action);
#endif
static int auth_action_ok(char *a,
gid_t gid,
gid_t *gl,
int gn,
gid_t egid);
static int auth_etc_enlightenment_sysactions(char *a,
char *u,
char **g);
static void auth_etc_enlightenment_sysactions_perm(char *path);
static char *get_word(char *s,
char *d);
/* local subsystem globals */
static Eina_Hash *actions = NULL;
static uid_t uid = -1;
/* externally accessible functions */
int
main(int argc,
char **argv)
{
int i, gn;
int test = 0;
char *action = NULL, *cmd;
#ifdef HAVE_EEZE_MOUNT
Eina_Bool mnt = EINA_FALSE;
const char *act = NULL;
#endif
gid_t gid, gl[65536], egid;
for (i = 1; i < argc; i++)
{
if ((!strcmp(argv[i], "-h")) ||
(!strcmp(argv[i], "-help")) ||
(!strcmp(argv[i], "--help")))
{
printf(
"This is an internal tool for Enlightenment.\n"
"do not use it.\n"
);
exit(0);
}
}
if (argc >= 3)
{
if ((argc == 3) && (!strcmp(argv[1], "-t")))
{
test = 1;
action = argv[2];
}
#ifdef HAVE_EEZE_MOUNT
else
{
const char *s;
s = strrchr(argv[1], '/');
if ((!s) || (!s[1])) exit(1); /* eeze always uses complete path */
s++;
if (strcmp(s, "mount") && strcmp(s, "umount") && strcmp(s, "eject")) exit(1);
mnt = EINA_TRUE;
act = s;
action = argv[1];
}
#endif
}
else if (argc == 2)
{
action = argv[1];
}
else
{
exit(1);
}
if (!action) exit(1);
eina_init();
uid = getuid();
gid = getgid();
egid = getegid();
gn = getgroups(65536, gl);
if (gn < 0)
{
printf("ERROR: MEMBER OF MORE THAN 65536 GROUPS\n");
exit(3);
}
if (setuid(0) != 0)
{
printf("ERROR: UNABLE TO ASSUME ROOT PRIVILEGES\n");
exit(5);
}
if (setgid(0) != 0)
{
printf("ERROR: UNABLE TO ASSUME ROOT GROUP PRIVILEGES\n");
exit(7);
}
if (!auth_action_ok(action, gid, gl, gn, egid))
{
printf("ERROR: ACTION NOT ALLOWED: %s\n", action);
exit(10);
}
/* we can add more levels of auth here */
/* when mounting, this will match the exact path to the exe,
* as required in sysactions.conf
* this is intentionally pedantic for security
*/
cmd = eina_hash_find(actions, action);
if (!cmd)
{
printf("ERROR: UNDEFINED ACTION: %s\n", action);
exit(20);
}
/* sanitize environment */
#ifdef HAVE_UNSETENV
# define NOENV(x) unsetenv(x)
/* pass 1 - just nuke known dangerous env vars brutally if possible via
* unsetenv(). if you don't have unsetenv... there's pass 2 and 3 */
NOENV("IFS");
NOENV("CDPATH");
NOENV("LOCALDOMAIN");
NOENV("RES_OPTIONS");
NOENV("HOSTALIASES");
NOENV("NLSPATH");
NOENV("PATH_LOCALE");
NOENV("COLORTERM");
NOENV("LANG");
NOENV("LANGUAGE");
NOENV("LINGUAS");
NOENV("TERM");
NOENV("LD_PRELOAD");
NOENV("LD_LIBRARY_PATH");
NOENV("SHLIB_PATH");
NOENV("LIBPATH");
NOENV("AUTHSTATE");
NOENV("DYLD_*");
NOENV("KRB_CONF*");
NOENV("KRBCONFDIR");
NOENV("KRBTKFILE");
NOENV("KRB5_CONFIG*");
NOENV("KRB5_KTNAME");
NOENV("VAR_ACE");
NOENV("USR_ACE");
NOENV("DLC_ACE");
NOENV("TERMINFO");
NOENV("TERMINFO_DIRS");
NOENV("TERMPATH");
NOENV("TERMCAP");
NOENV("ENV");
NOENV("BASH_ENV");
NOENV("PS4");
NOENV("GLOBIGNORE");
NOENV("SHELLOPTS");
NOENV("JAVA_TOOL_OPTIONS");
NOENV("PERLIO_DEBUG");
NOENV("PERLLIB");
NOENV("PERL5LIB");
NOENV("PERL5OPT");
NOENV("PERL5DB");
NOENV("FPATH");
NOENV("NULLCMD");
NOENV("READNULLCMD");
NOENV("ZDOTDIR");
NOENV("TMPPREFIX");
NOENV("PYTHONPATH");
NOENV("PYTHONHOME");
NOENV("PYTHONINSPECT");
NOENV("RUBYLIB");
NOENV("RUBYOPT");
# ifdef HAVE_ENVIRON
if (environ)
{
int again;
char *tmp, *p;
/* go over environment array again and again... safely */
do
{
again = 0;
/* walk through and find first entry that we don't like */
for (i = 0; environ[i]; i++)
{
/* if it begins with any of these, it's possibly nasty */
if ((!strncmp(environ[i], "LD_", 3)) ||
(!strncmp(environ[i], "_RLD_", 5)) ||
(!strncmp(environ[i], "LC_", 3)) ||
(!strncmp(environ[i], "LDR_", 3)))
{
/* unset it */
tmp = strdup(environ[i]);
if (!tmp) abort();
p = strchr(tmp, '=');
if (!p) abort();
*p = 0;
NOENV(tmp);
free(tmp);
/* and mark our do to try again from the start in case
* unsetenv changes environ ptr */
again = 1;
break;
}
}
}
while (again);
}
# endif
#endif
/* pass 2 - clear entire environment so it doesn't exist at all. if you
* can't do this... you're possibly in trouble... but the worst is still
* fixed in pass 3 */
#ifdef HAVE_CLEARENV
clearenv();
#else
# ifdef HAVE_ENVIRON
environ = NULL;
# endif
#endif
/* pass 3 - set path and ifs to minimal defaults */
putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin");
putenv("IFS= \t\n");
if ((!test)
#ifdef HAVE_EEZE_MOUNT
&& (!mnt)
#endif
)
return system(cmd);
#ifdef HAVE_EEZE_MOUNT
if (mnt)
{
int ret = 0;
const char *mp = NULL;
Eina_Strbuf *buf = NULL;
if (!act) exit(40);
if (!mount_args_check(argc, argv, act)) exit(40);
/* all options are deemed safe at this point, so away we go! */
if (!strcmp(act, "mount"))
{
struct stat s;
mp = argv[5];
if (stat("/media", &s))
{
mode_t um;
um = umask(0);
if (mkdir("/media", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH))
{
printf("ERROR: COULD NOT CREATE DIRECTORY /media\n");
exit(40);
}
umask(um);
}
else if (!S_ISDIR(s.st_mode))
{
printf("ERROR: NOT A DIRECTORY: /media\n");
exit(40);
}
if (stat(mp, &s))
{
mode_t um;
um = umask(0);
if (mkdir(mp, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH))
{
printf("ERROR: COULD NOT CREATE DIRECTORY %s\n", mp);
exit(40);
}
umask(um);
}
else if (!S_ISDIR(s.st_mode))
{
printf("ERROR: NOT A DIRECTORY: %s\n", mp);
exit(40);
}
}
buf = eina_strbuf_new();
if (!buf) exit(30);
for (i = 1; i < argc; i++)
eina_strbuf_append_printf(buf, "%s ", argv[i]);
ret = system(eina_strbuf_string_get(buf));
if ((!strcmp(act, "umount")) && (!ret))
{
Eina_Iterator *it;
char path[PATH_MAX];
const char *s;
struct stat st;
Eina_Bool rm = EINA_TRUE;
mp = strrchr(argv[2], '/');
if (!mp) return ret;
snprintf(path, sizeof(path), "/media%s", mp);
if (stat(path, &st)) return ret;
if (!S_ISDIR(st.st_mode)) return ret;
it = eina_file_ls(path);
EINA_ITERATOR_FOREACH(it, s)
{
/* don't delete any directories with files in them */
rm = EINA_FALSE;
eina_stringshare_del(s);
}
if (rm)
{
if (rmdir(path))
printf("ERROR: COULD NOT UNLINK MOUNT POINT %s\n", path);
}
}
return ret;
}
#endif
eina_shutdown();
return 0;
}
/* local subsystem functions */
#ifdef HAVE_EEZE_MOUNT
static Eina_Bool
mountopts_check(const char *opts)
{
char buf[64];
const char *p;
char *end;
unsigned long muid;
Eina_Bool nosuid, nodev, noexec, nuid;
nosuid = nodev = noexec = nuid = EINA_FALSE;
/* these are the only possible options which can be present here; check them strictly */
if (eina_strlcpy(buf, opts, sizeof(buf)) >= sizeof(buf)) return EINA_FALSE;
for (p = buf; p && p[1]; p = strchr(p + 1, ','))
{
if (p[0] == ',') p++;
#define CMP(OPT) \
if (!strncmp(p, OPT, sizeof(OPT) - 1))
CMP("nosuid,")
{
nosuid = EINA_TRUE;
continue;
}
CMP("nodev,")
{
nodev = EINA_TRUE;
continue;
}
CMP("noexec,")
{
noexec = EINA_TRUE;
continue;
}
CMP("utf8,") continue;
CMP("utf8=0,") continue;
CMP("utf8=1,") continue;
CMP("iocharset=utf8,") continue;
CMP("uid=")
{
p += 4;
errno = 0;
muid = strtoul(p, &end, 10);
if (muid == ULONG_MAX) return EINA_FALSE;
if (errno) return EINA_FALSE;
if (end[0] != ',') return EINA_FALSE;
if (muid != uid) return EINA_FALSE;
nuid = EINA_TRUE;
continue;
}
return EINA_FALSE;
}
if ((!nosuid) || (!nodev) || (!noexec) || (!nuid)) return EINA_FALSE;
return EINA_TRUE;
}
static Eina_Bool
check_uuid(const char *uuid)
{
const char *p;
for (p = uuid; p[0]; p++)
if ((!isalnum(*p)) && (*p != '-')) return EINA_FALSE;
return EINA_TRUE;
}
static Eina_Bool
mount_args_check(int argc, char **argv, const char *action)
{
Eina_Bool opts = EINA_FALSE;
struct stat st;
const char *node;
char buf[PATH_MAX];
if (!strcmp(action, "mount"))
{
/* will ALWAYS be:
/path/to/mount -o nosuid,uid=XYZ,[utf8,] UUID=XXXX-XXXX[-XXXX-XXXX] /media/$devnode
*/
if (argc != 6) return EINA_FALSE;
if (argv[2][0] == '-')
{
/* disallow any -options other than -o */
if (strcmp(argv[2], "-o")) return EINA_FALSE;
opts = mountopts_check(argv[3]);
}
if (!opts) return EINA_FALSE;
if (!strncmp(argv[4], "UUID=", sizeof("UUID=") - 1))
{
if (!check_uuid(argv[4] + 5)) return EINA_FALSE;
}
else
{
if (strncmp(argv[4], "/dev/", 5)) return EINA_FALSE;
if (stat(argv[4], &st)) return EINA_FALSE;
}
node = strrchr(argv[5], '/');
if (!node) return EINA_FALSE;
if (!node[1]) return EINA_FALSE;
if (node - argv[5] != 6) return EINA_FALSE;
snprintf(buf, sizeof(buf), "/dev%s", node);
if (stat(buf, &st)) return EINA_FALSE;
}
else if (!strcmp(action, "umount"))
{
/* will ALWAYS be:
/path/to/umount /dev/$devnode
*/
if (argc != 3) return EINA_FALSE;
if (strncmp(argv[2], "/dev/", 5)) return EINA_FALSE;
if (stat(argv[2], &st)) return EINA_FALSE;
node = strrchr(argv[2], '/');
if (!node) return EINA_FALSE;
if (!node[1]) return EINA_FALSE;
if (node - argv[2] != 4) return EINA_FALSE;
/* this is good, but it prevents umounting user-mounted removable media;
* need to figure out a better way...
*
snprintf(buf, sizeof(buf), "/media%s", node);
if (stat(buf, &st)) return EINA_FALSE;
if (!S_ISDIR(st.st_mode)) return EINA_FALSE;
*/
}
else if (!strcmp(action, "eject"))
{
/* will ALWAYS be:
/path/to/eject /dev/$devnode
*/
if (argc != 3) return EINA_FALSE;
if (strncmp(argv[2], "/dev/", 5)) return EINA_FALSE;
if (stat(argv[2], &st)) return EINA_FALSE;
node = strrchr(argv[2], '/');
if (!node) return EINA_FALSE;
if (!node[1]) return EINA_FALSE;
if (node - argv[2] != 4) return EINA_FALSE;
}
else return EINA_FALSE;
return EINA_TRUE;
}
#endif
static int
auth_action_ok(char *a,
gid_t gid,
gid_t *gl,
int gn,
gid_t egid)
{
struct passwd *pw;
struct group *gp;
char *usr = NULL, **grp, *g;
int ret, i, j;
pw = getpwuid(uid);
if (!pw) return 0;
usr = pw->pw_name;
if (!usr) return 0;
grp = alloca(sizeof(char *) * (gn + 1 + 1));
j = 0;
gp = getgrgid(gid);
if (gp)
{
grp[j] = gp->gr_name;
j++;
}
for (i = 0; i < gn; i++)
{
if (gl[i] != egid)
{
gp = getgrgid(gl[i]);
if (gp)
{
g = alloca(strlen(gp->gr_name) + 1);
strcpy(g, gp->gr_name);
grp[j] = g;
j++;
}
}
}
grp[j] = NULL;
/* first stage - check:
* PREFIX/etc/enlightenment/sysactions.conf
*/
ret = auth_etc_enlightenment_sysactions(a, usr, grp);
if (ret == 1) return 1;
else if (ret == -1)
return 0;
/* the DEFAULT - allow */
return 1;
}
static int
auth_etc_enlightenment_sysactions(char *a,
char *u,
char **g)
{
FILE *f;
char file[4096], buf[4096], id[4096], ugname[4096], perm[4096], act[4096];
char *p, *pp, *s, **gp;
int ok = 0;
size_t len, line = 0;
int allow = 0;
int deny = 0;
snprintf(file, sizeof(file), "/etc/enlightenment/sysactions.conf");
f = fopen(file, "r");
if (!f)
{
snprintf(file, sizeof(file), PACKAGE_SYSCONF_DIR "/enlightenment/sysactions.conf");
f = fopen(file, "r");
if (!f) return 0;
}
auth_etc_enlightenment_sysactions_perm(file);
while (fgets(buf, sizeof(buf), f))
{
line++;
len = strlen(buf);
if (len < 1) continue;
if (buf[len - 1] == '\n') buf[len - 1] = 0;
/* format:
*
* # comment
* user: username [allow:|deny:] halt reboot ...
* group: groupname [allow:|deny:] suspend ...
*/
if (buf[0] == '#') continue;
p = buf;
p = get_word(p, id);
p = get_word(p, ugname);
pp = p;
p = get_word(p, perm);
allow = 0;
deny = 0;
if (!strcmp(id, "user:"))
{
if (!fnmatch(ugname, u, 0))
{
if (!strcmp(perm, "allow:")) allow = 1;
else if (!strcmp(perm, "deny:"))
deny = 1;
else
goto malformed;
}
else
continue;
}
else if (!strcmp(id, "group:"))
{
Eina_Bool matched = EINA_FALSE;
for (gp = g; *gp; gp++)
{
if (!fnmatch(ugname, *gp, 0))
{
matched = EINA_TRUE;
if (!strcmp(perm, "allow:")) allow = 1;
else if (!strcmp(perm, "deny:"))
deny = 1;
else
goto malformed;
}
}
if (!matched) continue;
}
else if (!strcmp(id, "action:"))
{
while ((*pp) && (isspace(*pp)))
pp++;
s = eina_hash_find(actions, ugname);
if (s) eina_hash_del(actions, ugname, s);
if (!actions) actions = eina_hash_string_superfast_new(free);
eina_hash_add(actions, ugname, strdup(pp));
continue;
}
else if (id[0] == 0)
continue;
else
goto malformed;
for (;; )
{
p = get_word(p, act);
if (act[0] == 0) break;
if (!fnmatch(act, a, 0))
{
if (allow) ok = 1;
else if (deny)
ok = -1;
goto done;
}
}
continue;
malformed:
printf("WARNING: %s:%zu\n"
"LINE: '%s'\n"
"MALFORMED LINE. SKIPPED.\n",
file, line, buf);
}
done:
fclose(f);
return ok;
}
static void
auth_etc_enlightenment_sysactions_perm(char *path)
{
struct stat st;
if (stat(path, &st) == -1)
return;
if ((st.st_mode & S_IWGRP) || (st.st_mode & S_IXGRP) ||
(st.st_mode & S_IWOTH) || (st.st_mode & S_IXOTH))
{
printf("ERROR: CONFIGURATION FILE HAS BAD PERMISSIONS (writable by group and/or others)\n");
exit(10);
}
}
static char *
get_word(char *s,
char *d)
{
char *p1, *p2;
p1 = s;
p2 = d;
while (*p1)
{
if (p2 == d)
{
if (isspace(*p1))
{
p1++;
continue;
}
}
if (isspace(*p1)) break;
*p2 = *p1;
p1++;
p2++;
}
*p2 = 0;
return p1;
}

View File

@ -535,6 +535,17 @@ executable('enlightenment_alert',
install : true
)
executable('enlightenment_sys',
[ 'e_sys_main.c' ],
include_directories: include_directories('../..'),
dependencies : [dep_eina, dep_ecore, dep_bluez],
c_args : suid_cflags,
link_args : suid_ldflags,
install_dir : dir_e_utils,
install : true
)
suid_exes += join_paths(dir_e_utils, 'enlightenment_sys')
executable('enlightenment_ckpasswd',
'e_ckpasswd_main.c',
include_directories: include_directories('../..'),