/* * dbus_service.c * * 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 library 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 * Library General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Author: Jan Lipovsky */ #include #include #include #include #include #include #include #include #include #include "samba_share.h" #include "dbus_service.h" #include "sfshare_errors.h" /* DBUS metods */ #define ACTION_ID_SETUP_SHARE "org.fedoraproject.SimpleFileShare.setup_share" #define ASTION_ID_GET_SHARE_STATUS "org.fedoraproject.SimpleFileShare.get_share_status" #define ASTION_ID_DELETE_SHARE "org.fedoraproject.SimpleFileShare.delete_share" typedef struct DaemonObject DaemonObject; typedef struct DaemonObjectClass DaemonObjectClass; static PolkitSubject *subject_dbus = NULL; static PolkitAuthority *authority = NULL; gboolean is_authorized = FALSE; DBusGConnection *bus; DBusGProxy *bus_proxy; GType daemon_object_get_type (void); struct DaemonObject { GObject parent; }; struct DaemonObjectClass { GObjectClass parent; }; #define DAEMON_TYPE_OBJECT (daemon_object_get_type ()) #define DAEMON_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), DAEMON_TYPE_OBJECT, DaemonObject)) #define DAEMON_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DAEMON_TYPE_OBJECT, DaemonObjectClass)) #define DAEMON_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), DAEMON_TYPE_OBJECT)) #define DAEMON_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DAEMON_TYPE_OBJECT)) #define DAEMON_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DAEMON_TYPE_OBJECT, DaemonObjectClass)) G_DEFINE_TYPE(DaemonObject, daemon_object, G_TYPE_OBJECT) gboolean daemon_get_share_status (DaemonObject *obj, const gchar *path, gchar ***result, GError **error); /* Async calls */ gboolean daemon_setup_share (DaemonObject *obj, const gchar **parameters, DBusGMethodInvocation *context); gboolean daemon_delete_share (DaemonObject *obj,const gchar *path, DBusGMethodInvocation *context); #include "dbus_service_glue.h" /** * Return text of Error */ gchar * get_error_msg (Error_sfshare err) { gchar *errmsg; switch (err) { case ERROR_FAILED: errmsg = g_strdup ("Failed"); break; case ERROR_PERMISSION_DENIED: errmsg = g_strdup ("Permission denied"); break; case ERROR_FILE_NOT_EXIST: errmsg = g_strdup ("Config file does not exist"); break; case ERROR_CAN_NOT_OPEN_FILE: errmsg = g_strdup ("Can not open config file"); break; case ERROR_DIRECTORY_NOT_SHARED: errmsg = g_strdup ("Directory is not shared"); break; case ERROR_WRONG_NAME: errmsg = g_strdup ("Wrong name"); break; case ERROR_WRONG_PATH: errmsg = g_strdup ("Wrong path"); break; case ERROR_READONLY_WRITABLE: errmsg = g_strdup ("Read only is same as writable"); break; case ERROR_SHARE_NAME_EXIST: errmsg = g_strdup ("Share name already exist"); break; default: errmsg = g_strdup ("Unknow error type"); break; } return errmsg; } GQuark get_error_quark (void) { static GQuark ret = 0; if (ret == 0) { ret = g_quark_from_static_string ("sfshare_daemon_error"); } return ret; } /** Return error to context */ static void send_error (DBusGMethodInvocation *context, gint error_code, const gchar *format, ...) { GError *error; va_list args; gchar *message; va_start (args, format); message = g_strdup_vprintf (format, args); va_end (args); error = g_error_new (ERROR_QUARK, error_code, "%s", message); dbus_g_method_return_error (context, error); g_error_free (error); g_free (message); } /** * Create pointer to DaemonData filled with values from parameters */ DaemonData * daemon_data_new ( DBusGMethodInvocation *context, AuthorizedCallback auth_cb, const gchar **in) { DaemonData *ret; ret = g_new0 (DaemonData, 1); ret->context = context; ret->authorized_cb = auth_cb; ret->in = g_new0 (gchar *, 6); gint i = 0; while(in[i] != NULL) { ret->in[i] = g_strdup (in[i]); i++; } return ret; } /** * Free DaemonData pointer */ void daemon_data_free (DaemonData * data) { gint i; i = 0; while (data->in[i] != NULL) { g_free (data->in[i++]); } g_free (data); } /** * PolicyKit callback function */ static void check_authorization_cb (PolkitAuthority *authority, GAsyncResult *res, DaemonData *data) { GError *error; PolkitAuthorizationResult *result; is_authorized = FALSE; error = NULL; result = polkit_authority_check_authorization_finish (authority, res, &error); if (error != NULL) { send_error (data->context, ERROR_PERMISSION_DENIED, "Not authorized: %s", error->message); g_error_free (error); } else { if (polkit_authorization_result_get_is_authorized (result)) { is_authorized = TRUE; } else if (polkit_authorization_result_get_is_challenge (result)) { send_error (data->context, ERROR_PERMISSION_DENIED, "Authentication is required"); } else { send_error (data->context, ERROR_PERMISSION_DENIED, "Not authorized"); } } if(is_authorized) { /* Run authorized callback */ (* data->authorized_cb) (data); } daemon_data_free (data); } static void daemon_object_init (DaemonObject *obj) { } static void daemon_object_class_init (DaemonObjectClass *klass) { } /** * Handle incomming request - D-Bus get_share_status */ gboolean daemon_get_share_status (DaemonObject *obj, const gchar *path, gchar ***result, GError **error) { /* puts("daemon_get_share_status"); */ Error_sfshare err; err = smb_get_share_status (path, result); if (err != OK) { *error = g_error_new (ERROR_QUARK, err, "%s", get_error_msg(err)); return FALSE; } else return TRUE; } /** * Authorized call of smb_set_share - write or change share section */ void setup_share_authorized (gpointer data) { Error_sfshare err; DaemonData *dd = data; err = smb_set_share (dd->in); if (err != OK) { send_error (dd->context, err, "%s", get_error_msg(err)); } smb_reload_service (); /* Return */ dbus_g_method_return (dd->context); } /** * Dbus setup share - polkit authorization check */ gboolean daemon_setup_share (DaemonObject *obj,const gchar **parameters, DBusGMethodInvocation *context) { /* puts ("daemon_setup_share"); */ DaemonData *data; data = daemon_data_new (context, setup_share_authorized, parameters); subject_dbus = polkit_system_bus_name_new (dbus_g_method_get_sender (context)); polkit_authority_check_authorization (authority, subject_dbus, ACTION_ID_SETUP_SHARE, NULL, /* PolkitDetails */ POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE, NULL, (GAsyncReadyCallback) check_authorization_cb, data); return TRUE; } /** * Authorized call of smb_delete_share - delete share section */ void delete_share_authorized (gpointer data) { Error_sfshare err; DaemonData *dd = data; err = smb_delete_share(dd->in); if (err != OK) { send_error (dd->context, err, "%s", get_error_msg(err)); } smb_reload_service (); /* Return */ dbus_g_method_return (dd->context); } /** * Dbus delete share - polkit authorization check */ gboolean daemon_delete_share (DaemonObject *obj, const gchar *path, DBusGMethodInvocation *context) { /* puts("daemon_delete_share"); */ DaemonData *data; const gchar *in[2] = {path, NULL}; data = daemon_data_new (context, delete_share_authorized, in); subject_dbus = polkit_system_bus_name_new (dbus_g_method_get_sender (context)); polkit_authority_check_authorization (authority, subject_dbus, ASTION_ID_DELETE_SHARE, NULL, /* PolkitDetails */ POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE, NULL, (GAsyncReadyCallback) check_authorization_cb, data); return TRUE; } /** * Start of sfshare deamon */ int dbus_sfshare_start () { GError *error = NULL; GMainLoop *mainloop; guint request_name_result; DaemonObject *obj; g_type_init (); dbus_g_object_type_install_info (DAEMON_TYPE_OBJECT, &dbus_glib_daemon_object_info); mainloop = g_main_loop_new (NULL, FALSE); bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); if (!bus) { g_warning ("Couldn't connect to system bus : %s", error->message); g_error_free (error); return -1; } /* PolKit */ authority = polkit_authority_get (); bus_proxy = dbus_g_proxy_new_for_name (bus, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); if (!dbus_g_proxy_call (bus_proxy, "RequestName", &error, G_TYPE_STRING, "org.fedoraproject.SimpleFileShare", G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &request_name_result, G_TYPE_INVALID)) { g_warning("Failed to acquire org.fedoraproject.SimpleFileShare : %s", error->message); g_error_free (error); return -1; } obj = g_object_new (DAEMON_TYPE_OBJECT, NULL); dbus_g_connection_register_g_object (bus, "/org/fedoraproject/SimpleFileShare", G_OBJECT (obj)); g_print ("Simple File Share - service running\n"); g_main_loop_run (mainloop); g_object_unref (obj); return 0; }