diff -ru nautilus-2.16.0-orig/libnautilus-private/nautilus-file.c nautilus-2.16.0/libnautilus-private/nautilus-file.c --- nautilus-2.16.0-orig/libnautilus-private/nautilus-file.c 2006-08-29 04:28:12.000000000 -0400 +++ nautilus-2.16.0/libnautilus-private/nautilus-file.c 2006-09-16 16:01:39.000000000 -0400 @@ -3567,7 +3567,7 @@ * context * @file: NautilusFile representing the file in question. * - * Returns: Newly allocated string ready to display to the user. + * Returns: Newly allocated string ready to display to the user, or NULL. * **/ char * @@ -3600,6 +3600,133 @@ return translated; } +/** + * nautilus_file_get_selinux_matchpathcon: + * + * Get a user-displayable string representing a file's default selinux + * context (as from matchpathcon). Only works on local files. + * @file: NautilusFile representing the file in question. + * + * Returns: Newly allocated string ready to display to the user, or NULL. + * + **/ +char * +nautilus_file_get_selinux_matchpathcon (NautilusFile *file) +{ + char *translated; + char *raw; + char *uri; + char *fname; + + g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL); + + translated = NULL; +#ifdef HAVE_SELINUX + uri = nautilus_file_get_uri (file); + fname = gnome_vfs_get_local_path_from_uri (uri); + + if (!fname) { + return NULL; + } + + raw = NULL; + if (matchpathcon (fname, file->details->info->permissions, &raw) == 0) { + if (selinux_raw_to_trans_context (raw, &translated) == 0) { + char *tmp; + tmp = g_strdup (translated); + freecon (translated); + translated = tmp; + } + freecon (raw); + } + + g_free (fname); + g_free (uri); +#endif + + return translated; +} + +static void +set_selinux_context_callback (GnomeVFSAsyncHandle *handle, + GnomeVFSResult result, + GnomeVFSFileInfo *new_info, + gpointer callback_data) +{ + set_permissions_callback (handle, result, new_info, callback_data); +} + +void +nautilus_file_set_selinux_context (NautilusFile *file, + const char *selinux_context, + NautilusFileOperationCallback callback, + gpointer callback_data) +{ + Operation *op; + GnomeVFSURI *vfs_uri; + GnomeVFSFileInfo *partial_file_info; + GnomeVFSFileInfoOptions options; + char *rcontext; + + rcontext = NULL; + + /* this is probably mostly right... */ + if (!nautilus_file_can_set_permissions (file)) { + /* Claim that something changed even if the permission change failed. + * This makes it easier for some clients who see the "reverting" + * to the old permissions as "changing back". + */ + nautilus_file_changed (file); + (* callback) (file, GNOME_VFS_ERROR_ACCESS_DENIED, callback_data); + return; + } + + /* Test the permissions-haven't-changed case explicitly + * because we don't want to send the file-changed signal if + * nothing changed. + */ + if (!strcmp(selinux_context, file->details->info->selinux_context)) { + (* callback) (file, GNOME_VFS_OK, callback_data); + return; + } + +#ifdef HAVE_SELINUX + /* this is really const, but prototype is wrong, *sigh* */ + if (selinux_trans_to_raw_context((char *)selinux_context, &rcontext)) { + (* callback) (file, GNOME_VFS_ERROR_NO_MEMORY, callback_data); + return; + } + selinux_context = rcontext; +#endif + + /* Set up a context change operation. */ + op = operation_new (file, callback, callback_data); + op->use_slow_mime = file->details->got_slow_mime_type; + + options = NAUTILUS_FILE_DEFAULT_FILE_INFO_OPTIONS; + if (op->use_slow_mime) { + options |= GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE; + } + /* Change the file-on-disk context. */ + partial_file_info = gnome_vfs_file_info_new (); + g_free (partial_file_info->selinux_context); + partial_file_info->selinux_context = g_strdup (selinux_context); + vfs_uri = nautilus_file_get_gnome_vfs_uri (file); + gnome_vfs_async_set_file_info (&op->handle, + vfs_uri, partial_file_info, + GNOME_VFS_SET_FILE_INFO_SELINUX_CONTEXT, + options, + GNOME_VFS_PRIORITY_DEFAULT, + set_selinux_context_callback, op); + gnome_vfs_file_info_unref (partial_file_info); + gnome_vfs_uri_unref (vfs_uri); + +#ifdef HAVE_SELINUX + freecon (rcontext); +#endif +} + + static char * get_real_name (const char *name, const char *gecos) { @@ -3802,7 +3929,7 @@ GnomeVFSResult result, GnomeVFSFileInfo *new_info, gpointer callback_data) -{ +{ /* FIXME: this is identical to set_permissions_callback */ Operation *op; op = callback_data; Only in nautilus-2.16.0/libnautilus-private: nautilus-file.c~ Only in nautilus-2.16.0/libnautilus-private: nautilus-file.c.selinux diff -ru nautilus-2.16.0-orig/libnautilus-private/nautilus-file.h nautilus-2.16.0/libnautilus-private/nautilus-file.h --- nautilus-2.16.0-orig/libnautilus-private/nautilus-file.h 2006-08-29 04:28:12.000000000 -0400 +++ nautilus-2.16.0/libnautilus-private/nautilus-file.h 2006-09-11 14:43:12.000000000 -0400 @@ -200,6 +200,7 @@ GList * nautilus_file_get_settable_group_names (NautilusFile *file); gboolean nautilus_file_can_get_selinux_context (NautilusFile *file); char * nautilus_file_get_selinux_context (NautilusFile *file); +char * nautilus_file_get_selinux_matchpathcon (NautilusFile *file); /* "Capabilities". */ gboolean nautilus_file_can_read (NautilusFile *file); @@ -226,6 +227,10 @@ GnomeVFSFilePermissions permissions, NautilusFileOperationCallback callback, gpointer callback_data); +void nautilus_file_set_selinux_context (NautilusFile *file, + const char *selinux_context, + NautilusFileOperationCallback callback, + gpointer callback_data); void nautilus_file_rename (NautilusFile *file, const char *new_name, NautilusFileOperationCallback callback, Only in nautilus-2.16.0/libnautilus-private: nautilus-file.h.selinux diff -ru nautilus-2.16.0-orig/libnautilus-private/nautilus-file-operations.c nautilus-2.16.0/libnautilus-private/nautilus-file-operations.c --- nautilus-2.16.0-orig/libnautilus-private/nautilus-file-operations.c 2006-08-23 05:02:33.000000000 -0400 +++ nautilus-2.16.0/libnautilus-private/nautilus-file-operations.c 2006-09-18 15:48:34.000000000 -0400 @@ -62,6 +62,10 @@ #include "nautilus-trash-monitor.h" #include "nautilus-file-utilities.h" +#ifdef HAVE_SELINUX +#include +#endif + typedef enum TransferKind TransferKind; typedef struct TransferInfo TransferInfo; typedef struct IconPositionIterator IconPositionIterator; @@ -2908,6 +2912,7 @@ GnomeVFSFilePermissions file_mask; GnomeVFSFilePermissions dir_permissions; GnomeVFSFilePermissions dir_mask; + char *context; NautilusSetPermissionsCallback callback; gpointer callback_data; }; @@ -2935,6 +2940,8 @@ GnomeVFSURI *uri; char *uri_str; struct FileInfo *file_info; + int flags; + int options; info = callback_data; @@ -2965,10 +2972,18 @@ vfs_info->permissions = (file_info->permissions & ~info->file_mask) | info->file_permissions; + flags = GNOME_VFS_SET_FILE_INFO_PERMISSIONS; + options = GNOME_VFS_FILE_INFO_DEFAULT; + if (info->context) { + flags |= GNOME_VFS_SET_FILE_INFO_SELINUX_CONTEXT; + vfs_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SELINUX_CONTEXT; + options |= GNOME_VFS_FILE_INFO_GET_SELINUX_CONTEXT; + g_free (vfs_info->selinux_context); + vfs_info->selinux_context = g_strdup (info->context); + } gnome_vfs_async_set_file_info (&info->handle, uri, vfs_info, - GNOME_VFS_SET_FILE_INFO_PERMISSIONS, - GNOME_VFS_FILE_INFO_DEFAULT, + flags, options, GNOME_VFS_PRIORITY_DEFAULT, set_permissions_set_file_info, info); @@ -2976,7 +2991,6 @@ gnome_vfs_file_info_unref (vfs_info); g_free (file_info->name); g_free (file_info); - } static void @@ -3021,13 +3035,11 @@ } } - if (result != GNOME_VFS_OK) { /* Finished with this dir, work on the files */ info->current_file = NULL; set_permissions_set_file_info (NULL, GNOME_VFS_OK, NULL, info); } - } /* Also called for the toplevel dir */ @@ -3039,7 +3051,8 @@ { struct RecursivePermissionsInfo *info; char *uri_str; - + int options; + info = callback_data; if (result == GNOME_VFS_OK && handle != NULL) { @@ -3048,9 +3061,13 @@ g_free (uri_str); } + options = GNOME_VFS_FILE_INFO_DEFAULT; + if (info->context) { + options |= GNOME_VFS_FILE_INFO_GET_SELINUX_CONTEXT; + } gnome_vfs_async_load_directory_uri (&info->handle, info->current_dir, - GNOME_VFS_FILE_INFO_DEFAULT, + options, 50, GNOME_VFS_PRIORITY_DEFAULT, set_permissions_got_files, @@ -3062,6 +3079,8 @@ { struct DirInfo *dir_info; GnomeVFSFileInfo *vfs_info; + int flags; + int options; gnome_vfs_uri_unref (info->current_dir); @@ -3069,6 +3088,7 @@ /* No more directories, finished! */ info->callback (info->callback_data); /* All parts of info should be freed now */ + g_free (info->context); g_free (info); return; } @@ -3083,12 +3103,18 @@ vfs_info->permissions = (dir_info->permissions & ~info->dir_mask) | info->dir_permissions; - - gnome_vfs_async_set_file_info (&info->handle, - info->current_dir, - vfs_info, - GNOME_VFS_SET_FILE_INFO_PERMISSIONS, - GNOME_VFS_FILE_INFO_DEFAULT, + flags = GNOME_VFS_SET_FILE_INFO_PERMISSIONS; + options = GNOME_VFS_FILE_INFO_DEFAULT; + if (info->context) { + flags |= GNOME_VFS_SET_FILE_INFO_SELINUX_CONTEXT; + vfs_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SELINUX_CONTEXT; + options |= GNOME_VFS_FILE_INFO_GET_SELINUX_CONTEXT; + g_free (vfs_info->selinux_context); + vfs_info->selinux_context = g_strdup (info->context); + } + + gnome_vfs_async_set_file_info (&info->handle, info->current_dir, + vfs_info, flags, options, GNOME_VFS_PRIORITY_DEFAULT, set_permissions_load_dir, info); @@ -3103,6 +3129,7 @@ GnomeVFSFilePermissions file_mask, GnomeVFSFilePermissions dir_permissions, GnomeVFSFilePermissions dir_mask, + const char *context, NautilusSetPermissionsCallback callback, gpointer callback_data) { @@ -3116,6 +3143,22 @@ info->file_mask = file_mask; info->dir_permissions = dir_permissions; info->dir_mask = dir_mask; + if (context) { + char *rcontext; + + rcontext = info->context = NULL; +#ifdef HAVE_SELINUX + /* this is really const, but prototype is wrong, *sigh* */ + if (selinux_trans_to_raw_context((char *)context, &rcontext)) { + g_error ("selinux_trans_to_raw_context: failed to allocate bytes"); + return; + } + info->context = g_strdup (rcontext); + freecon (rcontext); +#endif + } else { + info->context = NULL; + } info->callback = callback; info->callback_data = callback_data; @@ -3123,6 +3166,8 @@ if (info->current_dir == NULL) { info->callback (info->callback_data); + /* All parts of info should be freed now */ + g_free (info->context); g_free (info); return; } Only in nautilus-2.16.0/libnautilus-private: nautilus-file-operations.c~ Only in nautilus-2.16.0/libnautilus-private: nautilus-file-operations.c.selinux diff -ru nautilus-2.16.0-orig/libnautilus-private/nautilus-file-operations.h nautilus-2.16.0/libnautilus-private/nautilus-file-operations.h --- nautilus-2.16.0-orig/libnautilus-private/nautilus-file-operations.h 2006-06-15 09:16:01.000000000 -0400 +++ nautilus-2.16.0/libnautilus-private/nautilus-file-operations.h 2006-09-11 14:43:12.000000000 -0400 @@ -76,6 +76,7 @@ GnomeVFSFilePermissions file_mask, GnomeVFSFilePermissions folder_permissions, GnomeVFSFilePermissions folder_mask, + const char *context, NautilusSetPermissionsCallback callback, gpointer callback_data); Only in nautilus-2.16.0/libnautilus-private: nautilus-file-operations.h.selinux diff -ru nautilus-2.16.0-orig/src/file-manager/fm-error-reporting.c nautilus-2.16.0/src/file-manager/fm-error-reporting.c --- nautilus-2.16.0-orig/src/file-manager/fm-error-reporting.c 2006-08-29 04:28:12.000000000 -0400 +++ nautilus-2.16.0/src/file-manager/fm-error-reporting.c 2006-09-11 14:43:12.000000000 -0400 @@ -251,6 +251,38 @@ g_free (message); } +void +fm_report_error_setting_selinux (NautilusFile *file, + GnomeVFSResult error, + GtkWindow *parent_window) +{ + char *file_name; + char *message; + + if (error == GNOME_VFS_OK) { + return; + } + + file_name = nautilus_file_get_display_name (file); + + switch (error) { + case GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM: + message = g_strdup_printf (_("Couldn't change the SELinux security context of \"%s\" because it is on a read-only disk"), + file_name); + break; + default: + /* We should invent decent error messages for every case we actually experience. */ + g_warning ("Hit unhandled case %d (%s) in fm_report_error_setting_permissions", + error, gnome_vfs_result_to_string (error)); + message = g_strdup_printf (_("Sorry, couldn't change the permissions of \"%s\"."), file_name); + } + + eel_show_error_dialog (_("The SELinux security context could not be changed."), message, parent_window); + + g_free (file_name); + g_free (message); +} + typedef struct _FMRenameData { char *name; NautilusFileOperationCallback callback; Only in nautilus-2.16.0/src/file-manager: fm-error-reporting.c.selinux diff -ru nautilus-2.16.0-orig/src/file-manager/fm-error-reporting.h nautilus-2.16.0/src/file-manager/fm-error-reporting.h --- nautilus-2.16.0-orig/src/file-manager/fm-error-reporting.h 2006-08-29 04:28:12.000000000 -0400 +++ nautilus-2.16.0/src/file-manager/fm-error-reporting.h 2006-09-11 14:43:12.000000000 -0400 @@ -39,7 +39,10 @@ GnomeVFSResult error_code, GtkWindow *parent_window); void fm_report_error_setting_permissions (NautilusFile *file, - GnomeVFSResult error_code, + GnomeVFSResult error_code, + GtkWindow *parent_window); +void fm_report_error_setting_selinux (NautilusFile *file, + GnomeVFSResult error_code, GtkWindow *parent_window); void fm_report_error_setting_owner (NautilusFile *file, GnomeVFSResult error_code, Only in nautilus-2.16.0/src/file-manager: fm-error-reporting.h.selinux diff -ru nautilus-2.16.0-orig/src/file-manager/fm-properties-window.c nautilus-2.16.0/src/file-manager/fm-properties-window.c --- nautilus-2.16.0-orig/src/file-manager/fm-properties-window.c 2006-08-29 04:28:13.000000000 -0400 +++ nautilus-2.16.0/src/file-manager/fm-properties-window.c 2006-09-18 16:41:58.000000000 -0400 @@ -83,6 +83,10 @@ #include #include +#ifdef HAVE_SELINUX +# include +#endif + #define PREVIEW_IMAGE_WIDTH 96 #define ROW_PAD 6 @@ -102,7 +106,7 @@ GtkWidget *icon_button; GtkWidget *icon_image; - GtkWidget *icon_chooser; + GtkWidget *icon_chooser; GtkWidget *name_label; GtkWidget *name_field; @@ -124,12 +128,15 @@ unsigned int owner_change_timeout; GList *permission_buttons; - GList *permission_combos; + GList *permission_combos; /* how is this deallocated???? */ + GList *selinux_combo; GHashTable *initial_permissions; gboolean has_recursive_apply; GList *value_fields; + GList *edit_fields; + GList *mime_list; gboolean deep_count_finished; @@ -208,6 +215,10 @@ GtkComboBox *combo); static void value_field_update (FMPropertiesWindow *window, GtkLabel *field); +static void edit_field_update (FMPropertiesWindow *window, + GtkEntry *field); +static void popup_field_update (FMPropertiesWindow *window, + GtkComboBox *entry); static void properties_window_update (FMPropertiesWindow *window, GList *files); static void is_directory_ready_callback (NautilusFile *file, @@ -235,10 +246,32 @@ int row, int column, const char *initial_text); +static void attach_selinux_data_edit_field (GtkEntry *entry, + char *attr_value, + char *def_attr_value); +static void attach_selinux_data_popup_field (GtkComboBox *comb, + char *attr_val, + char *def_attr_val); + G_DEFINE_TYPE (FMPropertiesWindow, fm_properties_window, GTK_TYPE_WINDOW); #define parent_class fm_properties_window_parent_class +static void +maybe_gtk_entry_set_text (GtkEntry *entry, const char *val) +{ + char *old_val; + + g_assert (GTK_IS_ENTRY (entry)); + + old_val = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); + + if (strcmp (old_val, val) != 0) { + gtk_entry_set_text (entry, val); + } + g_free(old_val); +} + static gboolean is_multi_file_window (FMPropertiesWindow *window) { @@ -259,6 +292,39 @@ return FALSE; } +static gboolean +multi_have_same_selinux_context (FMPropertiesWindow *window) +{ + GList *l; + char *cntx; + + cntx = NULL; + for (l = window->details->original_files; l != NULL; l = l->next) { + NautilusFile *file; + + file = NAUTILUS_FILE (l->data); + if (!nautilus_file_is_gone (file)) { + char *tmp; + + tmp = nautilus_file_get_string_attribute_with_default (file, "selinux_context"); + if (!cntx) { + cntx = tmp; + } else if (strcmp (cntx, tmp)) { + g_free (tmp); + g_free (cntx); + return FALSE; + } + else { + g_free (tmp); + } + } + } + + g_free (cntx); + + return TRUE; +} + static int get_not_gone_original_file_count (FMPropertiesWindow *window) { @@ -494,7 +560,7 @@ return; } - uris = g_strsplit (selection_data->data, "\r\n", 0); + uris = g_strsplit ((char *) selection_data->data, "\r\n", 0); exactly_one = uris[0] != NULL && (uris[1] == NULL || uris[1][0] == '\0'); @@ -575,7 +641,7 @@ static void set_name_field (FMPropertiesWindow *window, const gchar *original_name, - const gchar *name) + const gchar *name) { gboolean new_widget; gboolean use_label; @@ -641,11 +707,7 @@ * currently showing. This causes minimal ripples (e.g. * selection change). */ - gchar *displayed_name = gtk_editable_get_chars (GTK_EDITABLE (window->details->name_field), 0, -1); - if (strcmp (displayed_name, name) != 0) { - gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name); - } - g_free (displayed_name); + maybe_gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name); } } } @@ -721,7 +783,6 @@ name_field_restore_original_name (NautilusEntry *name_field) { const char *original_name; - char *displayed_name; original_name = (const char *) g_object_get_data (G_OBJECT (name_field), "original_name"); @@ -730,14 +791,8 @@ return; } - displayed_name = gtk_editable_get_chars (GTK_EDITABLE (name_field), 0, -1); - - if (strcmp (original_name, displayed_name) != 0) { - gtk_entry_set_text (GTK_ENTRY (name_field), original_name); - } + maybe_gtk_entry_set_text (GTK_ENTRY (name_field), original_name); nautilus_entry_select_all (name_field); - - g_free (displayed_name); } static void @@ -850,7 +905,7 @@ word = g_list_find_custom (keywords, keyword, (GCompareFunc) strcmp); eel_g_list_free_deep (keywords); - return (word != NULL); + return word != NULL; } static void @@ -1117,7 +1172,7 @@ b = b->next; } - return (a == b); + return a == b; } static GList * @@ -1199,6 +1254,14 @@ for (l = window->details->value_fields; l != NULL; l = l->next) { value_field_update (window, GTK_LABEL (l->data)); } + + for (l = window->details->edit_fields; l != NULL; l = l->next) { + edit_field_update (window, GTK_ENTRY (l->data)); + } + + for (l = window->details->selinux_combo; l != NULL; l = l->next) { + popup_field_update (window, GTK_COMBO_BOX (l->data)); + } } mime_list = get_mime_list (window); @@ -1379,6 +1442,111 @@ ellipsize_text); } +static void +edit_field_update_internal (GtkEntry *entry, + GList *file_list) +{ + const char *attr_name; + char *attr_value; + char *def_attr_value; + char *inconsistent_string; + + g_assert (GTK_IS_ENTRY (entry)); + + attr_name = g_object_get_data (G_OBJECT (entry), "file_attribute"); + inconsistent_string = g_object_get_data (G_OBJECT (entry), + "inconsistent_string"); + def_attr_value = g_object_get_data (G_OBJECT (entry), + "matchpathcon_cntx"); + + attr_value = file_list_get_string_attribute (file_list, attr_name, + inconsistent_string); + + maybe_gtk_entry_set_text (GTK_ENTRY (entry), attr_value); + + /* JFIXME: this isn't generic, *sigh* ... */ + attach_selinux_data_edit_field (entry, attr_value, def_attr_value); + g_free (attr_value); +} + +static void +edit_field_update (FMPropertiesWindow *window, GtkEntry *entry) +{ + gboolean use_original; + + if (gtk_widget_is_focus (GTK_WIDGET (entry))) { + return; + } + + use_original = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (entry), "show_original")); + + edit_field_update_internal (entry, + (use_original ? + window->details->original_files : + window->details->target_files)); +} + +static void +popup_field_update_internal (GtkComboBox *combo, + GList *file_list) +{ + const char *attr_name; + char *attr_value; + char *def_attr_value; + char *inconsistent_string; + char *cntx_type; + GtkTreeIter iter; + + g_assert (GTK_IS_COMBO_BOX (combo)); + + if (gtk_widget_is_focus (GTK_WIDGET (combo))) { + return; + } + + attr_name = g_object_get_data (G_OBJECT (combo), "file_attribute"); + inconsistent_string = g_object_get_data (G_OBJECT (combo), + "inconsistent_string"); + def_attr_value = g_object_get_data (G_OBJECT (combo), + "matchpathcon_cntx"); + + attr_value = file_list_get_string_attribute (file_list, attr_name, + inconsistent_string); + + /* JFIXME: this isn't generic, *sigh* ... */ + + if (gtk_combo_box_get_active_iter (combo, &iter)) { + GtkTreeModel *model = gtk_combo_box_get_model (combo); + + /* don't update, if it's identical */ + gtk_tree_model_get (model, &iter, 0, &cntx_type, -1); + if (cntx_type && strcmp (cntx_type, attr_value) == 0) { + g_free (attr_value); + return; + } + } + + attach_selinux_data_popup_field (combo, attr_value, def_attr_value); + + g_free (attr_value); +} + +static void +popup_field_update (FMPropertiesWindow *window, GtkComboBox *combo) +{ + gboolean use_original; + + if (window->details->selinux_combo) { + return; /* FIXME: must be true: horrible UI, if working */ + } + + use_original = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "show_original")); + + popup_field_update_internal (combo, + (use_original ? + window->details->original_files : + window->details->target_files)); +} + static GtkLabel * attach_label (GtkTable *table, int row, @@ -1430,6 +1598,45 @@ return attach_label (table, row, column, initial_text, FALSE, FALSE, FALSE, TRUE, FALSE); } +static GtkEntry * +attach_edit (GtkTable *table, + int row, + int column, + const char *initial_text, + gboolean right_aligned, + gboolean bold, + gboolean ellipsize_text, + gboolean selectable, + gboolean mnemonic) +{ + GtkWidget *entry_field; + + entry_field = nautilus_entry_new (); + gtk_entry_set_text (GTK_ENTRY (entry_field), initial_text); + + gtk_entry_set_alignment (GTK_ENTRY (entry_field), right_aligned ? 1 : 0); + gtk_widget_show (entry_field); + gtk_table_attach (table, entry_field, + column, column + 1, + row, row + 1, + ellipsize_text + ? GTK_FILL | GTK_EXPAND + : GTK_FILL, + 0, + 0, 0); + + return GTK_ENTRY (entry_field); +} + +static GtkEntry * +attach_edit_label (GtkTable *table, + int row, + int column, + const char *initial_text) +{ + return attach_edit (table, row, column, initial_text, FALSE, FALSE, FALSE, TRUE, FALSE); +} + static GtkLabel * attach_ellipsizing_value_label (GtkTable *table, int row, @@ -1489,6 +1696,672 @@ } static void +start_long_operation (FMPropertiesWindow *window) +{ + if (window->details->long_operation_underway == 0) { + /* start long operation */ + GdkCursor * cursor; + + cursor = gdk_cursor_new (GDK_WATCH); + gdk_window_set_cursor (GTK_WIDGET (window)->window, cursor); + gdk_cursor_unref (cursor); + } + window->details->long_operation_underway ++; +} + +static void +end_long_operation (FMPropertiesWindow *window) +{ + if (GTK_WIDGET (window)->window != NULL && + window->details->long_operation_underway == 1) { + /* finished !! */ + gdk_window_set_cursor (GTK_WIDGET (window)->window, NULL); + } + window->details->long_operation_underway--; +} + +static void +selinux_change_callback (NautilusFile *file, GnomeVFSResult result, gpointer callback_data) +{ + FMPropertiesWindow *window; + g_assert (callback_data != NULL); + + window = FM_PROPERTIES_WINDOW (callback_data); + end_long_operation (window); + + /* Report the error if it's an error. */ + fm_report_error_setting_selinux (file, result, NULL); + + g_object_unref (window); +} + +static void +selinux_done_editing (FMPropertiesWindow *window, char *selinux_context) +{ + GList *l; + + /* Accept changes. */ + for (l = window->details->target_files; l != NULL; l = l->next) { + NautilusFile *file; + + file = NAUTILUS_FILE (l->data); + + start_long_operation (window); + g_object_ref (window); + nautilus_file_set_selinux_context (file, selinux_context, + selinux_change_callback, + window); + } +} + +static gboolean +selinux_focus_out (NautilusEntry *entry, GdkEventFocus *event, gpointer cb_data) +{ + g_assert (NAUTILUS_IS_ENTRY (entry)); + g_assert (FM_IS_PROPERTIES_WINDOW (cb_data)); + + if (GTK_WIDGET_SENSITIVE (entry)) { + char *tmp; + + tmp = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); + selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp); + g_free (tmp); + } + + return FALSE; +} + +static void +selinux_entry_activate (NautilusEntry *entry, gpointer cb_data) +{ + char *tmp; + + g_assert (NAUTILUS_IS_ENTRY (entry)); + g_assert (FM_IS_PROPERTIES_WINDOW (cb_data)); + + tmp = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); + selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp); + g_free (tmp); + + nautilus_entry_select_all_at_idle (entry); +} + +/* NOTE: This modifies cntx */ +static void +selinux_split_cntx (char *cntx, + const char **ret_attr_u, + const char **ret_attr_r, + const char **ret_attr_t, + const char **ret_attr_s) +{ + const char *attr_u; + const char *attr_r; + const char *attr_t; + const char *attr_s; + + attr_u = cntx; + if (!(attr_r = strchr (attr_u, ':'))) { + attr_r = "object_r"; /* shouldn't happen */ + } else { + *((char *)attr_r++) = 0; + } + + if (!(attr_t = strchr (attr_r, ':'))) { + attr_t = "file_t"; /* shouldn't happen */ + } else { + *((char *)attr_t++) = 0; + } + + if ((attr_s = strchr (attr_t, ':'))) { + *((char *)attr_s++) = 0; + } + + *ret_attr_u = attr_u; + *ret_attr_r = attr_r; + *ret_attr_t = attr_t; + *ret_attr_s = attr_s; +} + +static void +selinux_popup_activate (GtkComboBox *comb, gpointer cb_data) +{ + char *cntx_type; + char *orig_type; + const char *attr_u; + const char *attr_r; + const char *attr_t; + const char *attr_s; + char *tmp; + GtkTreeIter iter; + + g_assert (GTK_IS_COMBO_BOX (comb)); + g_assert (FM_IS_PROPERTIES_WINDOW (cb_data)); + + if (!gtk_combo_box_get_active_iter (comb, &iter)) { + return; + } else { + + GtkTreeModel *model = gtk_combo_box_get_model (comb); + gtk_tree_model_get (model, &iter, 0, &cntx_type, -1); + } + + if (!(orig_type = g_object_get_data (G_OBJECT (comb), + "original_cntx"))) { + return; + } + orig_type = g_strdup (orig_type); + + selinux_split_cntx (orig_type, &attr_u, &attr_r, &attr_t, &attr_s); + tmp = g_strjoin (":", attr_u, attr_r, cntx_type, attr_s, NULL); + g_free (orig_type); + + selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp); + g_free (tmp); +} + +static char * +cust_type_next_line (GIOChannel *ioc_ctypes) +{ + char *data; + gsize term; + GError *errc; + + data = NULL; + term = 0; + errc = NULL; + + if (G_IO_STATUS_NORMAL == g_io_channel_read_line (ioc_ctypes, &data, + NULL, &term, &errc)) { + data[term] = 0; + return data; + } + + return NULL; +} + +static GSList * +selinux__type_list (void) +{ + static GSList *cust_types; + static time_t file_mtime; + const char *fname_ctypes; + struct stat buf; + GIOChannel *ioc_ctypes; + GError *errc; + GSList *scan; + int fd; + +#ifndef HAVE_SELINUX + if (cust_types) { + return cust_types; + } +#else + fname_ctypes = selinux_customizable_types_path (); + if (cust_types && file_mtime && !stat (fname_ctypes, &buf) && + (file_mtime == buf.st_mtime)) { + return cust_types; + } +#endif + + if (cust_types) { + for (scan = cust_types; scan; scan = scan->next) { + g_free (scan->data); + } + g_slist_free (cust_types); + cust_types = NULL; + } + + cust_types = g_slist_prepend (cust_types, g_strdup ("tmp_t")); + cust_types = g_slist_prepend (cust_types, g_strdup ("user_home_t")); + /* cust_types = g_slist_prepend (cust_types, g_strdup ("user_tmp_t")); */ + +#ifdef HAVE_SELINUX + /* read types, one per line... */ + fname_ctypes = selinux_customizable_types_path (); + errc = NULL; + if ((ioc_ctypes = g_io_channel_new_file (fname_ctypes, "r", &errc))) { + char *data = NULL; + + while ((data = cust_type_next_line (ioc_ctypes))) { + cust_types = g_slist_prepend (cust_types, data); + } + + fd = g_io_channel_unix_get_fd (ioc_ctypes); + if (!fstat (fd, &buf)) { + file_mtime = buf.st_mtime; + } + + g_io_channel_unref (ioc_ctypes); + } +#endif + + return cust_types; +} + +static void +attach_selinux_data_edit_field (GtkEntry *entry, + char *attr_val, char *def_attr_val) +{ + GtkEntryCompletion *comp; + GtkCellRenderer *cell; + const char *attr_u; + const char *attr_r; + const char *attr_t; + const char *attr_s; + const char *dattr_u; + const char *dattr_r; + const char *dattr_t; + const char *dattr_s; + GtkListStore *store; + GtkTreeIter iter; + GSList *scan; + int width; + int owidth; + int twidth; + + attr_val = g_strdup (attr_val); /* so we can alter it... */ + def_attr_val = g_strdup (def_attr_val); /* so we can alter it... */ + + /* do completion, so you don't have to type everything... */ + comp = gtk_entry_completion_new (); + store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + 0, GTK_SORT_ASCENDING); + + gtk_entry_completion_set_model (comp, GTK_TREE_MODEL (store)); + cell = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comp), cell, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comp), cell, + "stock-id", 1, NULL); + gtk_entry_completion_set_text_column (comp, 0); + gtk_entry_set_completion (entry, comp); + + /* FIXME: default doesn't do the right thing, should it? */ + owidth = gtk_entry_get_width_chars (entry); + width = owidth; + + selinux_split_cntx (attr_val, &attr_u, &attr_r, &attr_t, &attr_s); + if (def_attr_val) { + selinux_split_cntx (def_attr_val, &dattr_u, &dattr_r, + &dattr_t, &dattr_s); + } + + /* don't do it twice... */ + if (attr_t && dattr_t && !strcmp (attr_t, dattr_t)) { + dattr_t = NULL; + } + + if (attr_t) { + /* highlight just the type to the end, so we can easily change it + * FIXME: we also highlight any Sensitivity/MCS but completion will + * let people put it back, and that's the only way we get completion + * at all -- This sucks and we need to remove Sensitivity/MCS from + * the edit box. Yah, more UI. */ + int beg = attr_t - attr_u; + gtk_editable_select_region (GTK_EDITABLE (entry), beg, -1); + } + + for (scan = selinux__type_list(); scan; scan = scan->next) { + char *tmp; + + if (attr_t && !strcmp (attr_t, scan->data)) + continue; /* don't have two entries */ + + if (dattr_t && !strcmp (dattr_t, scan->data)) + continue; /* don't have two entries */ + + gtk_list_store_append (store, &iter); + tmp = g_strjoin (":", attr_u, attr_r, scan->data, attr_s, NULL); + gtk_list_store_set (store, &iter, 0, tmp, -1); + + twidth = strlen (tmp); + width = MAX (twidth, width); + + g_free (tmp); + } + + if (dattr_t) { + char *tmp; + + gtk_list_store_append (store, &iter); + tmp = g_strjoin (":", dattr_u, dattr_r, dattr_t, dattr_s, NULL); + gtk_list_store_set (store, &iter, 0, tmp, + 1, GTK_STOCK_HOME, -1); + + twidth = strlen (tmp); + width = MAX (twidth, width); + + g_free (tmp); + } + + if (attr_t) { + char *tmp; + + gtk_list_store_append (store, &iter); + tmp = g_strjoin (":", attr_u, attr_r, attr_t, attr_s, NULL); + gtk_list_store_set (store, &iter, 0, tmp, 1, GTK_STOCK_OK, -1); + + twidth = strlen (tmp); + width = MAX (twidth, width); + + g_free (tmp); + } + + g_free (attr_val); + g_free (def_attr_val); + g_object_unref (G_OBJECT (store)); + g_object_unref (G_OBJECT (comp)); + + if (width != owidth) { + gtk_entry_set_width_chars (entry, width + 2); + } +} + +# define HACK_TYPE(x, y) \ + else if (!strcmp (nice_type, x)) nice_type = y + +/* hack to convert a selinux_context type into a readable string for the + user */ +static const char * +selinux__hack_conv_type (const char *type) +{ /* FIXME: hack attack, but nowhere else to put it. Because mathpathcon + * here now probably want a bunch of other types? */ + const char *nice_type; + + nice_type = type; + + if (0) { } + + HACK_TYPE("cupsd_etc_t", _("CUPS printer configuration")); + HACK_TYPE("cupsd_rw_etc_t", _("CUPS printer configuration (rw)")); + HACK_TYPE("cupsd_tmp_t", _("CUPS temporary data")); + HACK_TYPE("dhcp_etc_t", _("DHCP configuration")); + HACK_TYPE("dictd_etc_t", _("Dictd configuration")); + HACK_TYPE("dnssec_t", _("DNS secret")); + HACK_TYPE("etc_t", _("System configuration")); + HACK_TYPE("etc_aliases_t", _("Email aliases configuration")); + HACK_TYPE("etc_runtime_t", _("System configuration (rw)")); + HACK_TYPE("cvs_data_t", _("Read and write from CVS daemon")); + HACK_TYPE("httpd_config_t", _("Apache-httpd configuration")); + HACK_TYPE("httpd_php_tmp_t", + _("Apache-httpd PHP module temporary data")); + HACK_TYPE("httpd_sys_content_t", + _("Read from all httpd scripts and the daemon")); + HACK_TYPE("httpd_sys_htaccess_t", + _("Apache-httpd .htaccess configuration")); + HACK_TYPE("httpd_sys_script_exec_t", + _("CGI programs with default access")); + HACK_TYPE("httpd_sys_script_ra_t", + _("CGI programs can read and append")); + HACK_TYPE("httpd_sys_script_ro_t", + _("CGI programs can read")); + HACK_TYPE("httpd_sys_script_rw_t", + _("CGI programs can read and write")); + HACK_TYPE("httpd_unconfined_script_exec_t", + _("CGI programs without any SELinux protection")); + HACK_TYPE("httpd_tmp_t", _("Apache-httpd temporary data")); + HACK_TYPE("ice_tmp_t", _("ICE temporary data")); + HACK_TYPE("locale_t", _("Locale data")); + HACK_TYPE("mysql_tmp_t", _("MySQL temporary data")); + HACK_TYPE("named_conf_t", _("Nameserver configuration")); + HACK_TYPE("net_conf_t", _("Network configuration")); + HACK_TYPE("postgresql_tmp_t", _("Postgresql temporary data")); + HACK_TYPE("public_content_rw_t", + _("Read and write from CIFS/ftp/http/nfs/rsync")); + HACK_TYPE("public_content_t", _("Read from CIFS/ftp/http/nfs/rsync")); + HACK_TYPE("samba_etc_t", _("Samba configuration")); + HACK_TYPE("samba_share_t", _("Shared via CIFS (samba)")); + HACK_TYPE("staff_home_t", _("Staff user data")); + HACK_TYPE("staff_home_dir_t", _("Staff user home directory")); + HACK_TYPE("swapfile_t", _("System swapfile")); + HACK_TYPE("sysadm_home_t", _("Sysadmin user data")); + HACK_TYPE("sysadm_home_dir_t", _("Sysadmin user home directory")); + HACK_TYPE("system_cron_spool_t", _("Cron data")); + HACK_TYPE("tmp_t", _("Temporary data")); + HACK_TYPE("user_tmp_t", _("User temporary data")); + HACK_TYPE("user_home_t", _("User data")); + HACK_TYPE("user_home_dir_t", _("User home directory")); + HACK_TYPE("var_log_t", _("Logfile")); + HACK_TYPE("xen_image_t", _("Xen image")); + + return nice_type; +} +#undef HACK_TYPE + +static void +attach_selinux_data_popup_field (GtkComboBox *comb, + char *attr_val, + char *def_attr_val) +{ + const char *attr_u; + const char *attr_r; + const char *attr_t; + const char *attr_s; + const char *dattr_u; + const char *dattr_r; + const char *dattr_t; + const char *dattr_s; + GtkListStore *store; + GtkTreeIter iter; + GSList *scan; + + attr_val = g_strdup (attr_val); /* so we can alter it... */ + def_attr_val = g_strdup (def_attr_val); + + /* do completion, so you don't have to type everything... */ + store = gtk_list_store_new (3, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + 1, GTK_SORT_ASCENDING); + + gtk_combo_box_set_model (comb, GTK_TREE_MODEL (store)); + + selinux_split_cntx (attr_val, &attr_u, &attr_r, &attr_t, &attr_s); + if (def_attr_val) { + selinux_split_cntx (def_attr_val, &dattr_u, &dattr_r, + &dattr_t, &dattr_s); + } + + /* don't do it twice... */ + if (attr_t && dattr_t && !strcmp (attr_t, dattr_t)) { + dattr_t = NULL; + } + + for (scan = selinux__type_list(); scan; scan = scan->next) { + const char *nice_type; + + if (attr_t && !strcmp (attr_t, scan->data)) + continue; /* don't have two entries */ + + if (dattr_t && !strcmp (dattr_t, scan->data)) + continue; /* don't have two entries */ + + nice_type = selinux__hack_conv_type(scan->data); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, scan->data, + 1, nice_type, -1); + } + + if (dattr_t) { + const char *nice_type; + + gtk_list_store_append (store, &iter); + nice_type = selinux__hack_conv_type(dattr_t); + gtk_list_store_set (store, &iter, 0, dattr_t, 1, nice_type, + 2, GTK_STOCK_HOME, -1); + } + + if (attr_t) { + const char *nice_type; + + gtk_list_store_append (store, &iter); + nice_type = selinux__hack_conv_type(attr_t); + gtk_list_store_set (store, &iter, 0, attr_t, 1, nice_type, + 2, GTK_STOCK_OK, -1); + gtk_combo_box_set_active_iter (comb, &iter); + } + + g_free (attr_val); + g_free (def_attr_val); + g_object_unref (G_OBJECT (store)); +} + +static char * +selinux__matchpathcon (GList *file_list) +{ + GList *scan; + + for (scan = file_list; scan != NULL; scan = scan->next) { + NautilusFile *file; + + file = NAUTILUS_FILE (scan->data); + if (!nautilus_file_is_gone (file)) { + return nautilus_file_get_selinux_matchpathcon (file); + } + } + + return NULL; +} + +static void +attach_selinux_edit_field (FMPropertiesWindow *window, + GtkTable *table, + int row, + int column, + const char *file_attribute_name, + const char *inconsistent_string, + gboolean show_original, + GtkLabel *lab_title) +{ + GtkEntry *entry; + GList *file_list; + char *attr_value; + char *def_attr_value; + + if (show_original) { + file_list = window->details->original_files; + } else { + file_list = window->details->target_files; + } + + attr_value = file_list_get_string_attribute (file_list, + file_attribute_name, + inconsistent_string); + if ( strcmp (attr_value, inconsistent_string) && + !strcmp (file_attribute_name, "selinux_context")) { + def_attr_value = selinux__matchpathcon (file_list); + } else { + def_attr_value = NULL; + } + + entry = attach_edit_label (table, row, column, attr_value); + gtk_label_set_mnemonic_widget (GTK_LABEL (lab_title), + GTK_WIDGET (entry)); + + /* Stash a copy of the file attribute name in this field for the callback's sake. */ + g_object_set_data_full (G_OBJECT (entry), "file_attribute", + g_strdup (file_attribute_name), g_free); + + g_object_set_data_full (G_OBJECT (entry), "inconsistent_string", + g_strdup (inconsistent_string), g_free); + + g_object_set_data (G_OBJECT (entry), "show_original", GINT_TO_POINTER (show_original)); + g_object_set_data (G_OBJECT (entry), "ellipsize_text", GINT_TO_POINTER (FALSE)); + + g_signal_connect_object (entry, "focus_out_event", + G_CALLBACK (selinux_focus_out), window, 0); + g_signal_connect_object (entry, "activate", + G_CALLBACK (selinux_entry_activate), window,0); + + attach_selinux_data_edit_field (entry, attr_value, def_attr_value); + + g_object_set_data_full (G_OBJECT (entry), "original_cntx", attr_value, + g_free); + + g_object_set_data_full (G_OBJECT (entry), "matchpathcon_cntx", + def_attr_value, g_free); + + window->details->edit_fields = g_list_prepend (window->details->edit_fields, + entry); +} + +static void +attach_selinux_popup_field (FMPropertiesWindow *window, + GtkTable *table, + int row, + int column, + const char *file_attribute_name, + const char *inconsistent_string, + gboolean show_original, + GtkLabel *lab_title) +{ + GtkWidget *comb; + GtkCellRenderer *cell; + GList *file_list; + char *attr_value; + char *def_attr_value; + + if (show_original) { + file_list = window->details->original_files; + } else { + file_list = window->details->target_files; + } + + attr_value = file_list_get_string_attribute (file_list, + file_attribute_name, + inconsistent_string); + if ( strcmp (attr_value, inconsistent_string) && + !strcmp (file_attribute_name, "selinux_context")) { + def_attr_value = selinux__matchpathcon (file_list); + } else { + def_attr_value = NULL; + } + + comb = gtk_combo_box_new (); + + gtk_table_attach (table, comb, column, column + 1, row, row + 1, + GTK_FILL, 0, 0, 0); + + + gtk_label_set_mnemonic_widget (GTK_LABEL (lab_title), comb); + + /* Stash a copy of the file attribute name in this field for the callback's sake. */ + g_object_set_data_full (G_OBJECT (comb), "file_attribute", + g_strdup (file_attribute_name), g_free); + + g_object_set_data (G_OBJECT (comb), "show_original", GINT_TO_POINTER (show_original)); + + attach_selinux_data_popup_field (GTK_COMBO_BOX (comb), + attr_value, def_attr_value); + + g_signal_connect_object (comb, "changed", + G_CALLBACK (selinux_popup_activate), window, 0); + + g_object_set_data_full (G_OBJECT (comb), "original_cntx", attr_value, + g_free); + + g_object_set_data_full (G_OBJECT (comb), "matchpathcon_cntx", + def_attr_value, g_free); + + cell = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comb), cell, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comb), cell, + "stock-id", 2, NULL); + cell = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comb), cell, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comb), cell, + "text", 1, NULL); + gtk_widget_show (comb); + + g_assert (! window->details->selinux_combo); + + window->details->selinux_combo = + g_list_prepend (window->details->selinux_combo, comb); + +} + +static void attach_ellipsizing_value_field (FMPropertiesWindow *window, GtkTable *table, int row, @@ -2425,7 +3298,7 @@ gboolean show_original) { guint last_row; - + last_row = append_title_field (table, title, NULL); attach_value_field (window, table, last_row, VALUE_COLUMN, file_attribute_name, @@ -2436,6 +3309,36 @@ } static guint +append_title_selinux_edit_pair (FMPropertiesWindow *window, + GtkTable *table, + const char *title, + const char *file_attribute_name, + const char *inconsistent_state, + gboolean show_original) +{ + guint last_row; + GtkLabel *lab_title; + + lab_title = NULL; + last_row = append_title_field (table, title, &lab_title); + + if (window->details->advanced_permissions) { + attach_selinux_edit_field (window, table, last_row, + VALUE_COLUMN, file_attribute_name, + inconsistent_state, + show_original, lab_title); + } else { + + attach_selinux_popup_field (window, table, last_row, + VALUE_COLUMN, file_attribute_name, + inconsistent_state, + show_original, lab_title); + } + + return last_row; +} + +static guint append_title_and_ellipsizing_value (FMPropertiesWindow *window, GtkTable *table, const char *title, @@ -2893,31 +3796,6 @@ } static void -start_long_operation (FMPropertiesWindow *window) -{ - if (window->details->long_operation_underway == 0) { - /* start long operation */ - GdkCursor * cursor; - - cursor = gdk_cursor_new (GDK_WATCH); - gdk_window_set_cursor (GTK_WIDGET (window)->window, cursor); - gdk_cursor_unref (cursor); - } - window->details->long_operation_underway ++; -} - -static void -end_long_operation (FMPropertiesWindow *window) -{ - if (GTK_WIDGET (window)->window != NULL && - window->details->long_operation_underway == 1) { - /* finished !! */ - gdk_window_set_cursor (GTK_WIDGET (window)->window, NULL); - } - window->details->long_operation_underway--; -} - -static void permission_change_callback (NautilusFile *file, GnomeVFSResult result, gpointer callback_data) { FMPropertiesWindow *window; @@ -4035,14 +4913,16 @@ GnomeVFSFilePermissions file_permission, file_permission_mask; GnomeVFSFilePermissions dir_permission, dir_permission_mask; GnomeVFSFilePermissions vfs_mask, vfs_new_perm, p; - GtkWidget *button, *combo; + char *context = NULL; + GtkWidget *button; + GtkComboBox *combo; gboolean active, is_folder, is_special, use_original; GList *l; GtkTreeModel *model; GtkTreeIter iter; PermissionType type; int new_perm, mask; - + file_permission = 0; file_permission_mask = 0; dir_permission = 0; @@ -4079,9 +4959,9 @@ } /* Simple mode, minus exec checkbox */ for (l = window->details->permission_combos; l != NULL; l = l->next) { - combo = l->data; + combo = GTK_COMBO_BOX (l->data); - if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) { + if (!gtk_combo_box_get_active_iter (combo, &iter)) { continue; } @@ -4089,7 +4969,7 @@ is_folder = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "is-folder")); - model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo)); + model = gtk_combo_box_get_model (combo); gtk_tree_model_get (model, &iter, 1, &new_perm, 2, &use_original, -1); if (use_original) { continue; @@ -4112,12 +4992,52 @@ } } + /* get the SELinux context... */ + if (window->details->advanced_permissions && + window->details->edit_fields) { /* advanced mode */ + GtkEditable *efield; + + efield = window->details->edit_fields->data; + context = gtk_editable_get_chars (GTK_EDITABLE (efield), 0, -1); + } else if (!window->details->advanced_permissions && + window->details->selinux_combo) { /* simple mode */ + char *cntx_type; + char *orig_type; + const char *attr_u; + const char *attr_r; + const char *attr_t; + const char *attr_s; + + combo = GTK_COMBO_BOX (window->details->selinux_combo->data); + + if (!gtk_combo_box_get_active_iter (combo, &iter)) { + return; + } else { + GtkTreeModel *model = gtk_combo_box_get_model (combo); + gtk_tree_model_get (model, &iter, 0, &cntx_type, -1); + } + if (!(orig_type = g_object_get_data (G_OBJECT (combo), + "original_cntx"))) { + return; + } + + orig_type = g_strdup (orig_type); + + selinux_split_cntx (orig_type, + &attr_u, &attr_r, &attr_t, &attr_s); + context = g_strjoin (":", + attr_u, attr_r, cntx_type, attr_s, NULL); + g_free (orig_type); + } + for (l = window->details->target_files; l != NULL; l = l->next) { NautilusFile *file; char *uri; file = NAUTILUS_FILE (l->data); + /* assume permissions setting allows context setting... + * we can't really do much else due to race conditions anyway */ if (nautilus_file_is_directory (file) && nautilus_file_can_set_permissions (file)) { uri = nautilus_file_get_uri (file); @@ -4128,11 +5048,13 @@ file_permission_mask, dir_permission, dir_permission_mask, + context, set_recursive_permissions_done, window); g_free (uri); } } + g_free (context); } static void @@ -4179,11 +5101,20 @@ } gtk_table_set_row_spacing (page_table, page_table->nrows - 1, 18); - - append_title_value_pair - (window, page_table, _("SELinux Context:"), - "selinux_context", _("--"), - FALSE); + + if (!is_multi_file_window (window) || + multi_have_same_selinux_context(window)) + append_title_selinux_edit_pair + (window, page_table, _("_SELinux Context:"), + "selinux_context", _("--"), + FALSE); + else /* Static text in this case. */ + append_title_value_pair (window, page_table, + _("_SELinux Context:"), + "selinux_context", _("--"), + FALSE); + + append_title_value_pair (window, page_table, _("Last changed:"), "date_permissions", _("--"), Only in nautilus-2.16.0/src/file-manager: fm-properties-window.c~ Only in nautilus-2.16.0/src/file-manager: fm-properties-window.c.selinux