From 2584d956c11867e2a6135f488c87e5017607c989 Mon Sep 17 00:00:00 2001 From: Petr Lautrbach Date: Jan 18 2018 13:41:11 +0000 Subject: [PATCH 1/3] framework: Open 3.3.15 development --- diff --git a/framework/configure.ac b/framework/configure.ac index 67b6f6c..04192d4 100644 --- a/framework/configure.ac +++ b/framework/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([setroubleshoot], [3.3.14], +AC_INIT([setroubleshoot], [3.3.15], [http://bugzilla.redhat.com/bugzilla/enter_bug.cgi?product=setroubleshoot]) AC_CONFIG_SRCDIR(src/setroubleshoot/__init__.py) From 853bb0b43f2b576772a0bb28da9fe930fc7dc7b2 Mon Sep 17 00:00:00 2001 From: Petr Lautrbach Date: Jan 18 2018 15:55:28 +0000 Subject: [PATCH 2/3] Rewrite seapplet to Python3 to use Notify and Gtk 3.0 Original seapplet was written in C using Gtk 2.0 and becomes obsolete after latest changes in GNOME 3 which dropped support for status icons. New seapplet still tries to show a status icon for environment where it's supported but uses new Notification Fixes or relates to: https://github.com/fedora-selinux/setroubleshoot/issues/50 https://pagure.io/setroubleshoot/issue/8 https://bugzilla.redhat.com/show_bug.cgi?id=1222797 --- diff --git a/framework/configure.ac b/framework/configure.ac index 04192d4..163e8a8 100644 --- a/framework/configure.ac +++ b/framework/configure.ac @@ -8,7 +8,6 @@ AM_INIT_AUTOMAKE AM_MAINTAINER_MODE PKG_CHECK_MODULES([DBUS], [dbus-1]) -PKG_CHECK_MODULES([GTK], [gtk+-3.0]) PKG_CHECK_MODULES([GIO], [gio-unix-2.0]) PKG_CHECK_MODULES([NOTIFY], [libnotify]) PKG_CHECK_MODULES([SEAPPLET], [gtk+-2.0 gio-unix-2.0 libnotify dbus-glib-1]) diff --git a/framework/src/seapplet.py b/framework/src/seapplet.py new file mode 100644 index 0000000..97f4f96 --- /dev/null +++ b/framework/src/seapplet.py @@ -0,0 +1,120 @@ +#!/usr/bin/python3 + +# Author: Petr Lautrbach +# Copyright (C) 2018 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gettext +import gi +from gi.repository import GLib +from gi.repository import GObject +from gi.repository import Gio +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk +gi.require_version('Notify', '0.7') +from gi.repository import Notify + +from pydbus import SystemBus + +from setroubleshoot.config import get_config + +class SEApplet(GObject.Object): + notifications = {} + notifications_number = 0 + + def __init__(self): + + bus = SystemBus() + self.bus_signal = bus.subscribe( + iface='org.fedoraproject.SetroubleshootdIface', + signal='alert', + signal_fired=self.send_notification + ) + + super(SEApplet, self).__init__() + Notify.init("seapplet") + + self.status_icon = Gtk.StatusIcon.new_from_file( + "/usr/share/icons/hicolor/scalable/apps/setroubleshoot_icon.svg" + ) + self.status_icon.connect("activate", self.status_show) + self.status_icon.set_visible(True) + # lets initialise with the application name + + # FIXME: + # if (check_for_avcs(&local_id) == TRUE) { + # sedbus_send_check_new(conn, (void *) &alert, local_id); + # } + + def dismiss(self, notification, action_name, data): + del self.notifications[notification] + self.status_icon.set_visible(False) + + def _close_notifications(self): + for n in self.notifications.keys(): + n.close() + + def status_show(self, status_icon): + self._close_notifications() + self.notifications.clear() + self.notifications_number = 0 + self.launch_desktop() + + def show(self, notification, action_name, data): + self._close_notifications() + self.notifications.clear() + self.notifications_number = 0 + self.launch_desktop() + + def launch_desktop(self): + launcher = Gio.DesktopAppInfo.new("setroubleshoot.desktop") + launcher.launch() + self.status_icon.set_visible(False) + + def send_notification(self, sender, dobject, iface, signal, params): + + # FIXME: + # AVC can be already ignored by a user + + # keep only one alert notification opened + self._close_notifications() + self.notifications_number += 1 + n = Notify.Notification.new( + _("New SELinux security alert"), + _("AVC denial, click icon to view"), + "/usr/share/icons/hicolor/scalable/apps/setroubleshoot_icon.svg" + ) + n.add_action("dismiss", _("Dismiss"), self.dismiss, None) + n.add_action("show", _("Show"), self.show, None) + n.add_action("default", _("Show"), self.show, None) + n.connect("closed", self.notification_closed) + n.show() + self.notifications[n] = params + + self.status_icon.set_visible(True) + + def notification_closed(self, notification): + del self.notifications[notification] + + +if __name__ == '__main__': + gettext.bindtextdomain(domain = get_config('general', 'i18n_text_domain'), + localedir = get_config('general', 'i18n_locale_dir')) + gettext.textdomain(domain = get_config('general', 'i18n_text_domain')) + _ = gettext.gettext + + my = SEApplet() + loop = GLib.MainLoop() + loop.run() From b234916cb0dc03301d28976fb01757a3d78dc191 Mon Sep 17 00:00:00 2001 From: Petr Lautrbach Date: Jan 18 2018 16:02:15 +0000 Subject: [PATCH 3/3] Rename original seapplet to seappletlegacy The original seapplet is now built as seappletlegacy. If you want to build it you need to use ./configure --enable-seappletlegacy --- diff --git a/framework/configure.ac b/framework/configure.ac index 163e8a8..186bb9a 100644 --- a/framework/configure.ac +++ b/framework/configure.ac @@ -10,7 +10,8 @@ AM_MAINTAINER_MODE PKG_CHECK_MODULES([DBUS], [dbus-1]) PKG_CHECK_MODULES([GIO], [gio-unix-2.0]) PKG_CHECK_MODULES([NOTIFY], [libnotify]) -PKG_CHECK_MODULES([SEAPPLET], [gtk+-2.0 gio-unix-2.0 libnotify dbus-glib-1]) +PKG_CHECK_MODULES([SEAPPLETLEGACY], [gtk+-2.0 gio-unix-2.0 libnotify dbus-glib-1], + [seappletlegacy=yes], [seappletlegacy=no]) # make sure we keep ACLOCAL_FLAGS around for maintainer builds to work AC_SUBST(ACLOCAL_AMFLAGS, "\${ACLOCAL_FLAGS}") @@ -55,6 +56,18 @@ AC_ARG_WITH([plugindir], AC_HELP_STRING([--with-plugindir=DIR], [plugindir="$with_plugindir"], [plugindir="\${datadir}/setroubleshoot/plugins"]) + +AC_ARG_ENABLE([seappletlegacy], + [AC_HELP_STRING([--enable-seappletlegacy], [build seappletlegacy (default=no)])], + [case "${enableval}" in + yes) seappletlegacy=yes ;; + no) seappletlegacy=no ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-seappletlegacy]) ;; + esac],[seappletlegacy=no]) + +AM_CONDITIONAL([ENABLE_SEAPPLETLEGACY], test "$seappletlegacy" = yes) + + AC_SUBST(pkgconfigdir) AC_SUBST(pkgdocdir) AC_SUBST(pkgguidir) diff --git a/framework/src/Makefile.am b/framework/src/Makefile.am index 725cb96..21cd516 100644 --- a/framework/src/Makefile.am +++ b/framework/src/Makefile.am @@ -1,27 +1,30 @@ bin_SCRIPTS = \ sealert \ + seapplet \ $(NULL) +sedispatch_CFLAGS = $(DBUS_CFLAGS) sedispatch_LDADD = $(CAPNG_LDADD) $(DBUS_LIBS) -lauparse -lselinux sedispatch_SOURCES = \ sedispatch.c \ sedbus.c -seapplet_LDADD = $(SEAPPLET_LIBS) -lauparse -lselinux -seapplet_SOURCES = \ - sedbus.h \ - seapplet.c \ + +if ENABLE_SEAPPLETLEGACY +seappletlegacy_LDADD = $(SEAPPLETLEGACY_LIBS) -lauparse -lselinux +seappletlegacy_SOURCES = \ + sedbus.h \ + seappletlegacy.c \ sedbus.c +AM_CPPFLAGS = $(SEAPPLETLEGACY_CFLAGS) +bin_PROGRAMS = seappletlegacy +endif -bin_PROGRAMS = \ - seapplet \ - $(NULL) sbin_PROGRAMS = \ sedispatch \ $(NULL) -AM_CPPFLAGS = $(SEAPPLET_CFLAGS) DEFS = @DEFS@ -DLOCALEDIR=\"$(localedir)\" diff --git a/framework/src/seapplet b/framework/src/seapplet new file mode 100644 index 0000000..97f4f96 --- /dev/null +++ b/framework/src/seapplet @@ -0,0 +1,120 @@ +#!/usr/bin/python3 + +# Author: Petr Lautrbach +# Copyright (C) 2018 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gettext +import gi +from gi.repository import GLib +from gi.repository import GObject +from gi.repository import Gio +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk +gi.require_version('Notify', '0.7') +from gi.repository import Notify + +from pydbus import SystemBus + +from setroubleshoot.config import get_config + +class SEApplet(GObject.Object): + notifications = {} + notifications_number = 0 + + def __init__(self): + + bus = SystemBus() + self.bus_signal = bus.subscribe( + iface='org.fedoraproject.SetroubleshootdIface', + signal='alert', + signal_fired=self.send_notification + ) + + super(SEApplet, self).__init__() + Notify.init("seapplet") + + self.status_icon = Gtk.StatusIcon.new_from_file( + "/usr/share/icons/hicolor/scalable/apps/setroubleshoot_icon.svg" + ) + self.status_icon.connect("activate", self.status_show) + self.status_icon.set_visible(True) + # lets initialise with the application name + + # FIXME: + # if (check_for_avcs(&local_id) == TRUE) { + # sedbus_send_check_new(conn, (void *) &alert, local_id); + # } + + def dismiss(self, notification, action_name, data): + del self.notifications[notification] + self.status_icon.set_visible(False) + + def _close_notifications(self): + for n in self.notifications.keys(): + n.close() + + def status_show(self, status_icon): + self._close_notifications() + self.notifications.clear() + self.notifications_number = 0 + self.launch_desktop() + + def show(self, notification, action_name, data): + self._close_notifications() + self.notifications.clear() + self.notifications_number = 0 + self.launch_desktop() + + def launch_desktop(self): + launcher = Gio.DesktopAppInfo.new("setroubleshoot.desktop") + launcher.launch() + self.status_icon.set_visible(False) + + def send_notification(self, sender, dobject, iface, signal, params): + + # FIXME: + # AVC can be already ignored by a user + + # keep only one alert notification opened + self._close_notifications() + self.notifications_number += 1 + n = Notify.Notification.new( + _("New SELinux security alert"), + _("AVC denial, click icon to view"), + "/usr/share/icons/hicolor/scalable/apps/setroubleshoot_icon.svg" + ) + n.add_action("dismiss", _("Dismiss"), self.dismiss, None) + n.add_action("show", _("Show"), self.show, None) + n.add_action("default", _("Show"), self.show, None) + n.connect("closed", self.notification_closed) + n.show() + self.notifications[n] = params + + self.status_icon.set_visible(True) + + def notification_closed(self, notification): + del self.notifications[notification] + + +if __name__ == '__main__': + gettext.bindtextdomain(domain = get_config('general', 'i18n_text_domain'), + localedir = get_config('general', 'i18n_locale_dir')) + gettext.textdomain(domain = get_config('general', 'i18n_text_domain')) + _ = gettext.gettext + + my = SEApplet() + loop = GLib.MainLoop() + loop.run() diff --git a/framework/src/seapplet.c b/framework/src/seapplet.c deleted file mode 100644 index d6ce7ec..0000000 --- a/framework/src/seapplet.c +++ /dev/null @@ -1,458 +0,0 @@ -/* - * seapplet.c - * - * Authors: John Dennis - * Authors: Dan Walsh - * - * Copyright (C) 2009 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * compile command - * gcc -g sealerttrayicon.c -o sealerttrayicon `pkg-config --cflags --libs gtk+-2.0` -lnotify - * - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "sedbus.h" -#include - -#ifdef ENABLE_NLS -#include /* for setlocale() */ -#include /* for gettext() */ -#define _(msgid) gettext (msgid) -#define P_(msgid, msgid_plural, n) ngettext(msgid, msgid_plural, n) -#else -#define _(msgid) (msgid) -#define P_(msgid, msgid_plural, n) (n==1 ? msgid : msgid_plural) -#endif -#ifndef PACKAGE -#define PACKAGE "setroubleshoot" /* the name of this package lang translation */ -#endif -static const char *PATH="/org/fedoraproject/Setroubleshootd"; -static const char *BUSNAME="org.fedoraproject.Setroubleshootd"; -static const char *INTERFACE="org.fedoraproject.SetroubleshootdIface"; - -typedef struct { - GtkStatusIcon *trayIcon; - NotifyNotification *notify; - guint32 need_bubble : 1; - gchar *redFile; - gchar *yellowFile; -} sealert; - -#define TIMEOUT (10 * 1000) -static gchar *icon_file = "/usr/share/icons/hicolor/scalable/apps/setroubleshoot_icon.svg"; -static gchar *redicon_file = "/usr/share/icons/hicolor/scalable/apps/setroubleshoot_red_icon.svg"; - -static char *configpath = NULL; - -static int ignore(const char *local_id) -{ - char *home; - const char *DTAG = "dontnotify="; - size_t dlen = strlen(DTAG); - char *buf=NULL; - - int ret = FALSE; - FILE *cfg = fopen(configpath, "r"); - if (cfg) { - size_t size = 0; - ssize_t len; - while ((len = getline(&buf, &size, cfg)) > 0) { - buf[len-1] = 0; - if (strncmp(buf, DTAG, dlen) == 0) { - int ctr=1; - char *ptr = buf+dlen; - while(*ptr) { - if (ptr[0] == ',') ctr++; - ptr++; - } - ptr = NULL; - char *tok = strtok_r(buf+dlen, ",", &ptr); - ctr=0; - while (tok) { - if (strcmp(tok, local_id) == 0) { - ret = TRUE; - goto DONE; - } - tok = strtok_r(NULL, ",", &ptr); - ctr++; - } - } - } -DONE: - fclose(cfg); - free(buf); - } - return ret; -} - -static void show_notification_now(sealert *alert) { - GError *err = NULL; -// notify_notification_attach_to_status_icon (alert->notify, alert->trayIcon); - notify_notification_show (alert->notify, &err); - if (err) { - g_warning ("Error showing notification: %s", err->message); - g_error_free (err); - } - alert->need_bubble = FALSE; -} - -static void on_notify_embedded_changed (sealert *alert) { - if (gtk_status_icon_is_embedded (alert->trayIcon) && alert->need_bubble) { - show_notification_now (alert); - } -} - -static void show_notification(sealert *alert) { - - if (gtk_status_icon_is_embedded (alert->trayIcon)) { - show_notification_now (alert); - } else { - g_signal_connect_swapped (alert->trayIcon, "notify::embedded", - G_CALLBACK (on_notify_embedded_changed), - alert); - alert->need_bubble = TRUE; - } - -} - -static void trayIconActivated(GObject *notused, gpointer ptr) -{ - GDesktopAppInfo *app; - GAppLaunchContext *context; - sealert *alert = (sealert*) ptr; - gtk_status_icon_set_visible(alert->trayIcon, FALSE); - alert->need_bubble = FALSE; - notify_notification_close (alert->notify, NULL); - app = g_desktop_app_info_new("setroubleshoot.desktop"); - context = (GAppLaunchContext*)gdk_app_launch_context_new (); - g_app_info_launch ((GAppInfo*) app, NULL, context, NULL); -} - - -static void on_activate(NotifyNotification *notification, - const char *action, - sealert *alert) { - if (strcmp(action, "dismiss") == 0) { - gtk_status_icon_set_visible(alert->trayIcon, FALSE); - alert->need_bubble = FALSE; - notify_notification_close (alert->notify, NULL); - } else { - trayIconActivated(NULL, alert); - } -} - -static void show_star(gpointer ptr, int red, char *local_id) { - sealert *alert = (sealert *) ptr; - gchar *file = NULL; - if (gtk_status_icon_get_visible (alert->trayIcon) && ! red ) { - return; - } - if (ignore(local_id)) - return; - - if (red) { - gtk_status_icon_set_from_file(alert->trayIcon, redicon_file); - file = alert->redFile; - - } else { - gtk_status_icon_set_from_file(alert->trayIcon, icon_file); - file = alert->yellowFile; - } - if ((! gtk_status_icon_get_visible (alert->trayIcon) || red ) && - alert->need_bubble == FALSE) { - gtk_status_icon_set_visible(alert->trayIcon, TRUE); - alert->notify = notify_notification_new(_("New SELinux security alert"),_("AVC denial, click icon to view"), red ? file : GTK_STOCK_DIALOG_WARNING); - if (!red) { - notify_notification_set_timeout (alert->notify, NOTIFY_EXPIRES_DEFAULT); - - notify_notification_add_action(alert->notify, - "dismiss", - _("Dismiss"), - (NotifyActionCallback) on_activate, - alert, - NULL); - } else { - notify_notification_set_timeout (alert->notify, NOTIFY_EXPIRES_NEVER); - } - - notify_notification_add_action(alert->notify, - "show", - _("Show"), - (NotifyActionCallback) on_activate, - alert, - NULL); - show_notification (alert); - } -} - -static void show_login_star(gpointer ptr, int yellow, int red) { - - sealert *alert = (sealert *) ptr; - gchar *file = NULL; - if (red) { - gtk_status_icon_set_from_file(alert->trayIcon, redicon_file); - file = alert->redFile; - - } else { - gtk_status_icon_set_from_file(alert->trayIcon, icon_file); - file = alert->yellowFile; - } - char msg [256]; - - sprintf(msg, P_("Since your last login, there is %d new security alert to view.", \ - "Since your last login, there are %d new security alerts to view.", yellow+red), yellow+red); - - if (red) - sprintf(msg+strlen(msg), " "); - sprintf(msg+strlen(msg), P_("%d of the alerts may be very serious security violations.", \ - "%d of the alerts may be very serious security violations.", red), red); - - char title[50]; - sprintf(title, P_("%d New Security Alert", "%d New Security Alerts", yellow+red), yellow+red); - gtk_status_icon_set_visible(alert->trayIcon, TRUE); - alert->notify = notify_notification_new(title, - msg, - red ? file : GTK_STOCK_DIALOG_WARNING); - if (!red) { - notify_notification_set_timeout (alert->notify, NOTIFY_EXPIRES_DEFAULT); - - notify_notification_add_action(alert->notify, - "dismiss", - _("Dismiss"), - (NotifyActionCallback) on_activate, - alert, - NULL); - } else { - notify_notification_set_timeout (alert->notify, NOTIFY_EXPIRES_NEVER); - } - - notify_notification_add_action(alert->notify, - "show", - _("Show"), - (NotifyActionCallback) on_activate, - alert, - NULL); - alert->need_bubble = TRUE; - show_notification_now (alert); -} - -static int sedbus_send_check_new(DBusConnection* conn, gpointer ptr, char *local_id) { - - DBusMessage* msg; - DBusMessageIter args; - DBusPendingCall* pending; - dbus_int32_t new_avcs = 0; - dbus_int32_t red_avcs = 0; - - msg = dbus_message_new_method_call(BUSNAME, - PATH, - INTERFACE, - "check_for_new"); // method name - if (NULL == msg) { - fprintf(stderr, "Can't communicate with setroubleshootd\n"); - return -1; - } - - int index = 0; - int id_found = 0; - int newlines = 0; - FILE *conf_file; - char c; - // append arguments - dbus_message_iter_init_append(msg, &args); - if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &local_id)) { - fprintf(stderr, "Out Of Memory!\n"); - return -1; - } - - // send message and get a handle for a reply - if ( ! dbus_connection_send_with_reply (conn, msg, &pending, -1)) { - // -1 is default timeout - fprintf(stderr, "Out Of Memory!\n"); - return -1; - } - if (NULL == pending) { - fprintf(stderr, "Pending Call Null\n"); - return -1; - } - dbus_connection_flush(conn); - - // free message - dbus_message_unref(msg); - - // block until we receive a reply - dbus_pending_call_block(pending); - - // get the reply message - msg = dbus_pending_call_steal_reply(pending); - if (NULL == msg) { - fprintf(stderr, "Reply Null\n"); - return -1; - } - // free the pending message handle - dbus_pending_call_unref(pending); - - // read the parameters - if (!dbus_message_iter_init(msg, &args)) - fprintf(stderr, "Message has no arguments!\n"); - else if (DBUS_TYPE_INT32!= dbus_message_iter_get_arg_type(&args)) - fprintf(stderr, "Argument is not int!\n"); - else - dbus_message_iter_get_basic(&args, &new_avcs); - - - if (!dbus_message_iter_next(&args)) - fprintf(stderr, "Message has no arguments!\n"); - else if (DBUS_TYPE_INT32 != dbus_message_iter_get_arg_type(&args)) - fprintf(stderr, "Argument is not int!\n"); - else - dbus_message_iter_get_basic(&args, &red_avcs); - - - // free reply and close connection - dbus_message_unref(msg); - - if (new_avcs + red_avcs == 0) - return 0; - - - show_login_star(ptr, new_avcs, red_avcs); - return 0; -} - -static int check_for_avcs(char *pos[]) -{ - const char *PTAG = "last="; - const char *CTAG = "checkonlogin="; - size_t plen = strlen(PTAG); - size_t clen = strlen(CTAG); - char *buf=NULL; - int check_on_login = 0; - FILE *cfg = fopen(configpath, "r"); - char *last = NULL; - if (cfg) { - size_t size = 0; - ssize_t len; - while ((len = getline(&buf, &size, cfg)) > 0) { - buf[len-1] = 0; - if (strncmp(buf, PTAG, plen) == 0) { - if (last) free(last); - last=strdup(buf + plen); - } - if (strncmp(buf, CTAG, clen) == 0) { - check_on_login=atoi(buf + clen); - } - } - fclose(cfg); - free(buf); - } - - if (check_on_login) { - if (last) - *pos = last; - else - *pos = calloc(sizeof(char*),1); - } else { - *pos = NULL; - free(last); - } - - return check_on_login; -} - -int main(int argc, char *argv[]) -{ - #ifdef ENABLE_NLS - bindtextdomain(PACKAGE, LOCALEDIR); - bind_textdomain_codeset(PACKAGE, "UTF-8"); - textdomain(PACKAGE); - #endif - - sealert alert; - - char *local_id=NULL; - - char *home; - - if (is_selinux_enabled() != 1) { - fprintf(stderr, "SELinux Troubleshooter: Applet requires SELinux be enabled to run.\n"); - return 1; - } - - home = getenv("HOME"); - if (asprintf(&configpath, "%s/.setroubleshoot", home) < 0) - return FALSE; - - int ctr = 0; - - gtk_init (&argc, &argv); - - notify_init ("Sealert notification"); - - GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_widget_set_size_request (window, 200, -1); - - alert.yellowFile = g_filename_to_uri (icon_file, NULL, NULL); - alert.redFile = g_filename_to_uri (redicon_file, NULL, NULL); - alert.trayIcon = gtk_status_icon_new_from_file (icon_file); - - //check with setroubleshoot server - - DBusError err; - DBusConnection* conn; - dbus_error_init(&err); - conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); - if (dbus_error_is_set(&err)) { - perror("error"); - dbus_error_free(&err); - } - if (NULL == conn){ - goto EXIT; - } - - - //set tooltip - gtk_status_icon_set_tooltip (alert.trayIcon, _("SELinux AVC denial, click to view")); - g_signal_connect(alert.trayIcon, "activate", GTK_SIGNAL_FUNC (trayIconActivated), &alert); - gtk_status_icon_set_visible(alert.trayIcon, FALSE); //set icon initially invisible - alert.need_bubble = FALSE; - - if (check_for_avcs(&local_id) == TRUE) { - sedbus_send_check_new(conn, (void *) &alert, local_id); - } - DBusConnection *conn2 = sedbus_receive(show_star, (void *) &alert); - dbus_connection_setup_with_g_main(conn2, NULL); - gtk_main (); - -EXIT: - free(configpath); - free(local_id); - ctr=0; - return 0; -} - diff --git a/framework/src/seapplet.py b/framework/src/seapplet.py deleted file mode 100644 index 97f4f96..0000000 --- a/framework/src/seapplet.py +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/python3 - -# Author: Petr Lautrbach -# Copyright (C) 2018 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import gettext -import gi -from gi.repository import GLib -from gi.repository import GObject -from gi.repository import Gio -gi.require_version('Gtk', '3.0') -from gi.repository import Gtk -gi.require_version('Notify', '0.7') -from gi.repository import Notify - -from pydbus import SystemBus - -from setroubleshoot.config import get_config - -class SEApplet(GObject.Object): - notifications = {} - notifications_number = 0 - - def __init__(self): - - bus = SystemBus() - self.bus_signal = bus.subscribe( - iface='org.fedoraproject.SetroubleshootdIface', - signal='alert', - signal_fired=self.send_notification - ) - - super(SEApplet, self).__init__() - Notify.init("seapplet") - - self.status_icon = Gtk.StatusIcon.new_from_file( - "/usr/share/icons/hicolor/scalable/apps/setroubleshoot_icon.svg" - ) - self.status_icon.connect("activate", self.status_show) - self.status_icon.set_visible(True) - # lets initialise with the application name - - # FIXME: - # if (check_for_avcs(&local_id) == TRUE) { - # sedbus_send_check_new(conn, (void *) &alert, local_id); - # } - - def dismiss(self, notification, action_name, data): - del self.notifications[notification] - self.status_icon.set_visible(False) - - def _close_notifications(self): - for n in self.notifications.keys(): - n.close() - - def status_show(self, status_icon): - self._close_notifications() - self.notifications.clear() - self.notifications_number = 0 - self.launch_desktop() - - def show(self, notification, action_name, data): - self._close_notifications() - self.notifications.clear() - self.notifications_number = 0 - self.launch_desktop() - - def launch_desktop(self): - launcher = Gio.DesktopAppInfo.new("setroubleshoot.desktop") - launcher.launch() - self.status_icon.set_visible(False) - - def send_notification(self, sender, dobject, iface, signal, params): - - # FIXME: - # AVC can be already ignored by a user - - # keep only one alert notification opened - self._close_notifications() - self.notifications_number += 1 - n = Notify.Notification.new( - _("New SELinux security alert"), - _("AVC denial, click icon to view"), - "/usr/share/icons/hicolor/scalable/apps/setroubleshoot_icon.svg" - ) - n.add_action("dismiss", _("Dismiss"), self.dismiss, None) - n.add_action("show", _("Show"), self.show, None) - n.add_action("default", _("Show"), self.show, None) - n.connect("closed", self.notification_closed) - n.show() - self.notifications[n] = params - - self.status_icon.set_visible(True) - - def notification_closed(self, notification): - del self.notifications[notification] - - -if __name__ == '__main__': - gettext.bindtextdomain(domain = get_config('general', 'i18n_text_domain'), - localedir = get_config('general', 'i18n_locale_dir')) - gettext.textdomain(domain = get_config('general', 'i18n_text_domain')) - _ = gettext.gettext - - my = SEApplet() - loop = GLib.MainLoop() - loop.run() diff --git a/framework/src/seappletlegacy.c b/framework/src/seappletlegacy.c new file mode 100644 index 0000000..d6ce7ec --- /dev/null +++ b/framework/src/seappletlegacy.c @@ -0,0 +1,458 @@ +/* + * seapplet.c + * + * Authors: John Dennis + * Authors: Dan Walsh + * + * Copyright (C) 2009 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * compile command + * gcc -g sealerttrayicon.c -o sealerttrayicon `pkg-config --cflags --libs gtk+-2.0` -lnotify + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "sedbus.h" +#include + +#ifdef ENABLE_NLS +#include /* for setlocale() */ +#include /* for gettext() */ +#define _(msgid) gettext (msgid) +#define P_(msgid, msgid_plural, n) ngettext(msgid, msgid_plural, n) +#else +#define _(msgid) (msgid) +#define P_(msgid, msgid_plural, n) (n==1 ? msgid : msgid_plural) +#endif +#ifndef PACKAGE +#define PACKAGE "setroubleshoot" /* the name of this package lang translation */ +#endif +static const char *PATH="/org/fedoraproject/Setroubleshootd"; +static const char *BUSNAME="org.fedoraproject.Setroubleshootd"; +static const char *INTERFACE="org.fedoraproject.SetroubleshootdIface"; + +typedef struct { + GtkStatusIcon *trayIcon; + NotifyNotification *notify; + guint32 need_bubble : 1; + gchar *redFile; + gchar *yellowFile; +} sealert; + +#define TIMEOUT (10 * 1000) +static gchar *icon_file = "/usr/share/icons/hicolor/scalable/apps/setroubleshoot_icon.svg"; +static gchar *redicon_file = "/usr/share/icons/hicolor/scalable/apps/setroubleshoot_red_icon.svg"; + +static char *configpath = NULL; + +static int ignore(const char *local_id) +{ + char *home; + const char *DTAG = "dontnotify="; + size_t dlen = strlen(DTAG); + char *buf=NULL; + + int ret = FALSE; + FILE *cfg = fopen(configpath, "r"); + if (cfg) { + size_t size = 0; + ssize_t len; + while ((len = getline(&buf, &size, cfg)) > 0) { + buf[len-1] = 0; + if (strncmp(buf, DTAG, dlen) == 0) { + int ctr=1; + char *ptr = buf+dlen; + while(*ptr) { + if (ptr[0] == ',') ctr++; + ptr++; + } + ptr = NULL; + char *tok = strtok_r(buf+dlen, ",", &ptr); + ctr=0; + while (tok) { + if (strcmp(tok, local_id) == 0) { + ret = TRUE; + goto DONE; + } + tok = strtok_r(NULL, ",", &ptr); + ctr++; + } + } + } +DONE: + fclose(cfg); + free(buf); + } + return ret; +} + +static void show_notification_now(sealert *alert) { + GError *err = NULL; +// notify_notification_attach_to_status_icon (alert->notify, alert->trayIcon); + notify_notification_show (alert->notify, &err); + if (err) { + g_warning ("Error showing notification: %s", err->message); + g_error_free (err); + } + alert->need_bubble = FALSE; +} + +static void on_notify_embedded_changed (sealert *alert) { + if (gtk_status_icon_is_embedded (alert->trayIcon) && alert->need_bubble) { + show_notification_now (alert); + } +} + +static void show_notification(sealert *alert) { + + if (gtk_status_icon_is_embedded (alert->trayIcon)) { + show_notification_now (alert); + } else { + g_signal_connect_swapped (alert->trayIcon, "notify::embedded", + G_CALLBACK (on_notify_embedded_changed), + alert); + alert->need_bubble = TRUE; + } + +} + +static void trayIconActivated(GObject *notused, gpointer ptr) +{ + GDesktopAppInfo *app; + GAppLaunchContext *context; + sealert *alert = (sealert*) ptr; + gtk_status_icon_set_visible(alert->trayIcon, FALSE); + alert->need_bubble = FALSE; + notify_notification_close (alert->notify, NULL); + app = g_desktop_app_info_new("setroubleshoot.desktop"); + context = (GAppLaunchContext*)gdk_app_launch_context_new (); + g_app_info_launch ((GAppInfo*) app, NULL, context, NULL); +} + + +static void on_activate(NotifyNotification *notification, + const char *action, + sealert *alert) { + if (strcmp(action, "dismiss") == 0) { + gtk_status_icon_set_visible(alert->trayIcon, FALSE); + alert->need_bubble = FALSE; + notify_notification_close (alert->notify, NULL); + } else { + trayIconActivated(NULL, alert); + } +} + +static void show_star(gpointer ptr, int red, char *local_id) { + sealert *alert = (sealert *) ptr; + gchar *file = NULL; + if (gtk_status_icon_get_visible (alert->trayIcon) && ! red ) { + return; + } + if (ignore(local_id)) + return; + + if (red) { + gtk_status_icon_set_from_file(alert->trayIcon, redicon_file); + file = alert->redFile; + + } else { + gtk_status_icon_set_from_file(alert->trayIcon, icon_file); + file = alert->yellowFile; + } + if ((! gtk_status_icon_get_visible (alert->trayIcon) || red ) && + alert->need_bubble == FALSE) { + gtk_status_icon_set_visible(alert->trayIcon, TRUE); + alert->notify = notify_notification_new(_("New SELinux security alert"),_("AVC denial, click icon to view"), red ? file : GTK_STOCK_DIALOG_WARNING); + if (!red) { + notify_notification_set_timeout (alert->notify, NOTIFY_EXPIRES_DEFAULT); + + notify_notification_add_action(alert->notify, + "dismiss", + _("Dismiss"), + (NotifyActionCallback) on_activate, + alert, + NULL); + } else { + notify_notification_set_timeout (alert->notify, NOTIFY_EXPIRES_NEVER); + } + + notify_notification_add_action(alert->notify, + "show", + _("Show"), + (NotifyActionCallback) on_activate, + alert, + NULL); + show_notification (alert); + } +} + +static void show_login_star(gpointer ptr, int yellow, int red) { + + sealert *alert = (sealert *) ptr; + gchar *file = NULL; + if (red) { + gtk_status_icon_set_from_file(alert->trayIcon, redicon_file); + file = alert->redFile; + + } else { + gtk_status_icon_set_from_file(alert->trayIcon, icon_file); + file = alert->yellowFile; + } + char msg [256]; + + sprintf(msg, P_("Since your last login, there is %d new security alert to view.", \ + "Since your last login, there are %d new security alerts to view.", yellow+red), yellow+red); + + if (red) + sprintf(msg+strlen(msg), " "); + sprintf(msg+strlen(msg), P_("%d of the alerts may be very serious security violations.", \ + "%d of the alerts may be very serious security violations.", red), red); + + char title[50]; + sprintf(title, P_("%d New Security Alert", "%d New Security Alerts", yellow+red), yellow+red); + gtk_status_icon_set_visible(alert->trayIcon, TRUE); + alert->notify = notify_notification_new(title, + msg, + red ? file : GTK_STOCK_DIALOG_WARNING); + if (!red) { + notify_notification_set_timeout (alert->notify, NOTIFY_EXPIRES_DEFAULT); + + notify_notification_add_action(alert->notify, + "dismiss", + _("Dismiss"), + (NotifyActionCallback) on_activate, + alert, + NULL); + } else { + notify_notification_set_timeout (alert->notify, NOTIFY_EXPIRES_NEVER); + } + + notify_notification_add_action(alert->notify, + "show", + _("Show"), + (NotifyActionCallback) on_activate, + alert, + NULL); + alert->need_bubble = TRUE; + show_notification_now (alert); +} + +static int sedbus_send_check_new(DBusConnection* conn, gpointer ptr, char *local_id) { + + DBusMessage* msg; + DBusMessageIter args; + DBusPendingCall* pending; + dbus_int32_t new_avcs = 0; + dbus_int32_t red_avcs = 0; + + msg = dbus_message_new_method_call(BUSNAME, + PATH, + INTERFACE, + "check_for_new"); // method name + if (NULL == msg) { + fprintf(stderr, "Can't communicate with setroubleshootd\n"); + return -1; + } + + int index = 0; + int id_found = 0; + int newlines = 0; + FILE *conf_file; + char c; + // append arguments + dbus_message_iter_init_append(msg, &args); + if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &local_id)) { + fprintf(stderr, "Out Of Memory!\n"); + return -1; + } + + // send message and get a handle for a reply + if ( ! dbus_connection_send_with_reply (conn, msg, &pending, -1)) { + // -1 is default timeout + fprintf(stderr, "Out Of Memory!\n"); + return -1; + } + if (NULL == pending) { + fprintf(stderr, "Pending Call Null\n"); + return -1; + } + dbus_connection_flush(conn); + + // free message + dbus_message_unref(msg); + + // block until we receive a reply + dbus_pending_call_block(pending); + + // get the reply message + msg = dbus_pending_call_steal_reply(pending); + if (NULL == msg) { + fprintf(stderr, "Reply Null\n"); + return -1; + } + // free the pending message handle + dbus_pending_call_unref(pending); + + // read the parameters + if (!dbus_message_iter_init(msg, &args)) + fprintf(stderr, "Message has no arguments!\n"); + else if (DBUS_TYPE_INT32!= dbus_message_iter_get_arg_type(&args)) + fprintf(stderr, "Argument is not int!\n"); + else + dbus_message_iter_get_basic(&args, &new_avcs); + + + if (!dbus_message_iter_next(&args)) + fprintf(stderr, "Message has no arguments!\n"); + else if (DBUS_TYPE_INT32 != dbus_message_iter_get_arg_type(&args)) + fprintf(stderr, "Argument is not int!\n"); + else + dbus_message_iter_get_basic(&args, &red_avcs); + + + // free reply and close connection + dbus_message_unref(msg); + + if (new_avcs + red_avcs == 0) + return 0; + + + show_login_star(ptr, new_avcs, red_avcs); + return 0; +} + +static int check_for_avcs(char *pos[]) +{ + const char *PTAG = "last="; + const char *CTAG = "checkonlogin="; + size_t plen = strlen(PTAG); + size_t clen = strlen(CTAG); + char *buf=NULL; + int check_on_login = 0; + FILE *cfg = fopen(configpath, "r"); + char *last = NULL; + if (cfg) { + size_t size = 0; + ssize_t len; + while ((len = getline(&buf, &size, cfg)) > 0) { + buf[len-1] = 0; + if (strncmp(buf, PTAG, plen) == 0) { + if (last) free(last); + last=strdup(buf + plen); + } + if (strncmp(buf, CTAG, clen) == 0) { + check_on_login=atoi(buf + clen); + } + } + fclose(cfg); + free(buf); + } + + if (check_on_login) { + if (last) + *pos = last; + else + *pos = calloc(sizeof(char*),1); + } else { + *pos = NULL; + free(last); + } + + return check_on_login; +} + +int main(int argc, char *argv[]) +{ + #ifdef ENABLE_NLS + bindtextdomain(PACKAGE, LOCALEDIR); + bind_textdomain_codeset(PACKAGE, "UTF-8"); + textdomain(PACKAGE); + #endif + + sealert alert; + + char *local_id=NULL; + + char *home; + + if (is_selinux_enabled() != 1) { + fprintf(stderr, "SELinux Troubleshooter: Applet requires SELinux be enabled to run.\n"); + return 1; + } + + home = getenv("HOME"); + if (asprintf(&configpath, "%s/.setroubleshoot", home) < 0) + return FALSE; + + int ctr = 0; + + gtk_init (&argc, &argv); + + notify_init ("Sealert notification"); + + GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_size_request (window, 200, -1); + + alert.yellowFile = g_filename_to_uri (icon_file, NULL, NULL); + alert.redFile = g_filename_to_uri (redicon_file, NULL, NULL); + alert.trayIcon = gtk_status_icon_new_from_file (icon_file); + + //check with setroubleshoot server + + DBusError err; + DBusConnection* conn; + dbus_error_init(&err); + conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); + if (dbus_error_is_set(&err)) { + perror("error"); + dbus_error_free(&err); + } + if (NULL == conn){ + goto EXIT; + } + + + //set tooltip + gtk_status_icon_set_tooltip (alert.trayIcon, _("SELinux AVC denial, click to view")); + g_signal_connect(alert.trayIcon, "activate", GTK_SIGNAL_FUNC (trayIconActivated), &alert); + gtk_status_icon_set_visible(alert.trayIcon, FALSE); //set icon initially invisible + alert.need_bubble = FALSE; + + if (check_for_avcs(&local_id) == TRUE) { + sedbus_send_check_new(conn, (void *) &alert, local_id); + } + DBusConnection *conn2 = sedbus_receive(show_star, (void *) &alert); + dbus_connection_setup_with_g_main(conn2, NULL); + gtk_main (); + +EXIT: + free(configpath); + free(local_id); + ctr=0; + return 0; +} +