src/moonshot-password-dialog.c
src/moonshot-provisioning-common-new.vala
src/moonshot-provisioning-common.c
-src/moonshot-server.c
+src/moonshot-server-linux.c
+src/moonshot-server-msrpc.c
src/moonshot-settings.c
src/moonshot-trust-anchor-dialog.c
src/moonshot-utils.c
src/moonshot-custom-vbox.vala \
src/moonshot-identities-manager.vala \
src/moonshot-identity-request.vala \
- src/moonshot-server.vala \
+ src/moonshot-server-linux.vala \
src/moonshot-settings.vala \
src/moonshot-password-dialog.vala \
src/moonshot-provisioning-common.vala \
#include <assert.h>
#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dbus/dbus-glib.h>
return success;
}
+
+int moonshot_confirm_ca_certificate (const char *identity_name,
+ const char *realm,
+ const unsigned char *ca_hash,
+ int hash_len,
+ MoonshotError **error)
+{
+ GError *g_error = NULL;
+ int success = 99;
+ int confirmed = 99;
+ char hash_str[65];
+ DBusGProxy *dbus_proxy = get_dbus_proxy (error);
+ int out = 0;
+ int i;
+
+ if (*error != NULL) {
+ return FALSE;
+ }
+
+ g_return_val_if_fail (DBUS_IS_G_PROXY (dbus_proxy), FALSE);
+
+ /* Convert hash byte array to string */
+ out = 0;
+ for (i = 0; i < hash_len; i++) {
+ sprintf(&(hash_str[out]), "%02X", ca_hash[i]);
+ out += 2;
+ }
+
+ printf("moonshot_confirm_ca_certificate: calling ConfirmCaCertificate; hash='%s'\n", hash_str);
+
+ int call_ok = dbus_g_proxy_call_with_timeout (dbus_proxy,
+ "ConfirmCaCertificate",
+ INFINITE_TIMEOUT,
+ &g_error,
+ G_TYPE_STRING, identity_name,
+ G_TYPE_STRING, realm,
+ G_TYPE_STRING, hash_str,
+ G_TYPE_INVALID,
+ G_TYPE_INT, &confirmed,
+ G_TYPE_BOOLEAN, &success,
+ G_TYPE_INVALID);
+
+ printf("moonshot_confirm_ca_certificate: back from ConfirmCaCertificate. call_ok=%d; confirmed=%d; success=%d\n",
+ (call_ok? 1 : 0), confirmed, success);
+
+ g_object_unref (dbus_proxy);
+
+ if (g_error != NULL) {
+ *error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
+ g_error->message);
+ return FALSE;
+ }
+
+ return (int) confirmed;
+}
moonshot_error_new
moonshot_get_default_identity
moonshot_get_identity
+ moonshot_confirm_ca_certificate
int force_flat_file_store,
MoonshotError **error);
+
+
+/**
+ * moonshot_confirm_ca_certificate
+ * @
+ * Return value: %TRUE if the certificate is approved; %FALSE otherwise
+ */
+
+int moonshot_confirm_ca_certificate (const char *identity_name,
+ const char *realm,
+ const unsigned char *sha256,
+ int sha256_length,
+ MoonshotError **error);
+
+
#endif
string? server_cert,
int force_flat_file_store,
out Moonshot.Error error);
+
+ [CCode (cname = "moonshot_confirm_ca_certificate")]
+ public bool moonshot_confirm_ca_certificate (string identity_name,
+ string realm,
+ string ca_hash,
+ out uint32 confirmed,
+ out Moonshot.Error error);
}
id_card_widget.position = next_pos++;
}
- public IdCardWidget? find_idcard_widget(IdCard id_card) {
+ public IdCardWidget? find_idcard_widget(IdCard card) {
+ if (card == null) {
+ return null;
+ }
foreach (var w in get_children()) {
IdCardWidget widget = (IdCardWidget) w;
- if (widget.id_card.nai == id_card.nai) {
+ if (widget.id_card == card) {
return widget;
}
}
private static const string CERT_FOOTER = "-----END CERTIFICATE-----";
public enum TrustAnchorType {
+ EMPTY,
CA_CERT,
SERVER_CERT
}
private string _subject_alt = "";
private string _server_cert = "";
private string _datetime_added = "";
- public bool user_verified = false;
private static string fixup (string s) {
return (s == null ? "" : s.strip());
}
- public TrustAnchor(string ca_cert, string server_cert, string subject, string subject_alt, bool user_verified) {
+ public TrustAnchor(string ca_cert, string server_cert, string subject, string subject_alt) {
_ca_cert = fixup(ca_cert);
_server_cert = fixup(server_cert);
_subject = fixup(subject);
_subject_alt = fixup(subject_alt);
- this.user_verified = user_verified;
// If we're reading from store, this will be overridden (see set_datetime_added)
_datetime_added = "";
}
public bool is_empty() {
- return ca_cert == "" && subject == "" && subject_alt == "" && server_cert == "";
+ return ca_cert == "" && server_cert == "";
}
public TrustAnchorType get_anchor_type() {
- return server_cert == "" ? TrustAnchorType.CA_CERT : TrustAnchorType.SERVER_CERT;
+ return (server_cert != "" ? TrustAnchorType.SERVER_CERT
+ : (ca_cert != "" ? TrustAnchorType.CA_CERT : TrustAnchorType.EMPTY));
}
internal void set_datetime_added(string datetime) {
return dt;
}
+ internal void update_server_fingerprint(string fingerprint) {
+ this._server_cert = fingerprint;
+ string ta_datetime_added = TrustAnchor.format_datetime_now();
+ this.set_datetime_added(ta_datetime_added);
+ }
+
public int Compare(TrustAnchor other)
{
if (this.ca_cert != other.ca_cert) {
return 1;
}
- // Do not compare the user_verified and datetime_added fields; they are not essential.
+ // Do not compare the datetime_added fields; it's not essential.
return 0;
}
public bool store_password { get; set; default = false; }
+ // uuid is currently used only for debugging. Must be unique, even between cards with same nai and display name.
+ public string uuid {
+ public get {return _uuid;}
+ }
+ private string _uuid = generate_uuid();
+
+ internal static string generate_uuid() {
+ uint32 rand1 = Random.next_int();
+ uint32 rand2 = Random.next_int();
+ return "%08X.%08X::%s".printf(rand1, rand2, TrustAnchor.format_datetime_now());
+ }
+
public bool is_no_identity()
{
return (display_name == NO_IDENTITY);
public IdCard id_card { get; set; default = null; }
private VBox main_vbox;
- private HBox table;
+ private HBox hbox;
private EventBox event_box;
private bool is_selected = false;
private Arrow arrow;
- private Label label;
+ private VBox details;
internal int _position = 0;
internal int position {
public void expand()
{
is_selected = true;
- update_id_card_label();
+ details.show_all();
set_idcard_color();
arrow.set(ArrowType.DOWN, ARROW_SHADOW);
public void collapse()
{
is_selected = false;
- update_id_card_label();
+ details.hide();
set_idcard_color();
arrow.set(ArrowType.RIGHT, ARROW_SHADOW);
}
private void
- update_id_card_label()
+ make_id_card_label(Label label)
{
- // !!TODO: Use a table to format the labels and values
- string service_spacer = "\n ";
-
var display_name = (manager_view.selection_in_progress() && this.id_card.is_no_identity()
? _("Do not use a Moonshot identity for this service") : this.id_card.display_name);
var label_text = Markup.printf_escaped("<span rise='8000'><big>%s</big></span>", display_name);
- if (is_selected)
- {
- if (!this.id_card.is_no_identity()) {
- label_text += "\n" + _("Username") + ": " + id_card.username;
- label_text += "\n" + _("Realm:") + " " + id_card.issuer;
- if (!id_card.trust_anchor.is_empty()) {
- label_text += "\n" + _("Trust anchor: Enterprise provisioned");
- }
- }
-
- string services_text = _("Services: ") + this.id_card.get_services_string(service_spacer);
- label_text += "\n" + services_text;
- }
-
label.set_markup(label_text);
}
this.id_card = id_card;
this.manager_view = manager_view;
- label = new Label(null);
- label.set_alignment((float) 0, (float) 0.5);
- label.set_ellipsize(Pango.EllipsizeMode.END);
- update_id_card_label();
-
- table = new Gtk.HBox(false, 6);
+ var display_name_label = new Label(null);
+ display_name_label.set_alignment((float) 0, (float) 0.5);
+ display_name_label.set_ellipsize(Pango.EllipsizeMode.END);
+ make_id_card_label(display_name_label);
+
+ var details_wrapper = new VBox(false, 0);
+ details_wrapper.pack_start(display_name_label, false, false, 0);
+ this.details = new VBox(false, 0);
+ details_wrapper.pack_start(details, false, false, 0);
+
+ if (!this.id_card.is_no_identity()) {
+ var upper_details_text = _("Username") + ": " + id_card.username;
+ upper_details_text += "\n" + _("Realm:") + " " + id_card.issuer;
+ if (!id_card.trust_anchor.is_empty()) {
+ upper_details_text += "\n" + _("Trust anchor: Enterprise provisioned");
+ }
+ Label upper_details = new Label(upper_details_text);
+ upper_details.set_alignment(0, 0);
+ details.pack_start(upper_details);
+ }
+ var services_hbox = new HBox(false, 6);
+ Label services_label = new Label(_("Services: "));
+ services_label.set_alignment(0, 0);
+
+ string services_text = this.id_card.get_services_string("\n");
+ Label service_list = new Label(services_text);
+ service_list.set_alignment(0, 0);
+ service_list.set_ellipsize(Pango.EllipsizeMode.END);
+ service_list.set_max_width_chars(50);
+ services_hbox.pack_start(services_label, false, false, 0);
+ services_hbox.pack_start(service_list, false, false, 0);
+ details.pack_start(services_hbox);
+
+ hbox = new Gtk.HBox(false, 6);
var image = new Image.from_pixbuf(get_pixbuf(id_card));
if (this.id_card.is_no_identity()) {
image.clear();
// Use padding to make the image size = 48x48 (size = 2x padding)
image.set_padding(24, 24);
}
- table.pack_start(image, false, false, 0);
- table.pack_start(label, true, true, 0);
+ hbox.pack_start(image, false, false, 0);
+ hbox.pack_start(details_wrapper, true, true, 0);
this.arrow = new Arrow(ArrowType.RIGHT, ARROW_SHADOW);
- table.pack_start(arrow, false, false);
+ this.arrow.set_alignment((float) 0.5, (float) 0);
+ hbox.pack_start(arrow, false, false);
this.main_vbox = new VBox(false, 12);
- main_vbox.pack_start(table, true, true, 0);
+ main_vbox.pack_start(hbox, true, true, 0);
main_vbox.set_border_width(12);
event_box = new EventBox();
this.pack_start(event_box, true, true);
this.show_all();
+ details.hide();
set_idcard_color();
}
remove_card_internal(id_card);
if (new_card.trust_anchor.Compare(id_card.trust_anchor) == 0) {
- logger.trace("Old and new cards have same trust anchor. Re-using the datetime_added and user_verified fields from the old card.");
+ logger.trace("Old and new cards have same trust anchor. Re-using the datetime_added field from the old card.");
new_card.trust_anchor.set_datetime_added(id_card.trust_anchor.datetime_added);
- new_card.trust_anchor.user_verified = id_card.trust_anchor.user_verified;
}
}
return (dups.size > 0);
}
+
+ public bool find_duplicate_nai_sets(out ArrayList<ArrayList<IdCard>> duplicates)
+ {
+ var nais = new HashMap<string, ArrayList<IdCard>>();
+
+ duplicates = new ArrayList<ArrayList<IdCard>>();
+ LinkedList<IdCard> card_list = get_card_list() ;
+ if (card_list == null) {
+ return false;
+ }
+
+ bool found = false;
+ foreach (IdCard id_card in card_list) {
+ logger.trace(@"load_id_cards: Loading card with display name '$(id_card.display_name)'");
+
+ //!!TODO: This uniqueness check really belongs somewhere else -- like where we add
+ // IDs, and/or read them from storage. However, we should never hit this.
+
+ if (nais.has_key(id_card.nai)) {
+ ArrayList<IdCard> list = nais.get(id_card.nai);
+ list.add(id_card);
+ }
+ else {
+ ArrayList<IdCard> list = new ArrayList<IdCard>();
+ list.add(id_card);
+ nais.set(id_card.nai, list);
+ }
+ }
+
+ duplicates = new ArrayList<ArrayList<IdCard>>();
+ foreach (Map.Entry<string, ArrayList<IdCard>> entry in nais.entries) {
+ var list = entry.value;
+ if (list.size > 1) {
+ duplicates.add(list);
+ found = true;
+ }
+ }
+ return found;
+ }
+
+
public IdCard? find_id_card(string nai, bool force_flat_file_store) {
IdCard? retval = null;
IIdentityCardStore.StoreType saved_store_type = get_store_type();
this.set_border_width(6);
this.set_resizable(false);
- this.modify_bg(StateType.NORMAL, white);
+ set_bg_color(this);
this.show_all();
}
row++;
if (id.trust_anchor.get_anchor_type() == TrustAnchor.TrustAnchorType.SERVER_CERT) {
- Widget fingerprint = make_ta_fingerprint_widget(id.trust_anchor);
- ta_table.attach(fingerprint, 0, 1, row, row + 2, fill_and_expand, fill_and_expand, 5, 5);
+ Widget fingerprint = make_ta_fingerprint_widget(id.trust_anchor.server_cert);
+ // ta_table.attach(fingerprint, 0, 1, row, row + 2, fill_and_expand, fill_and_expand, 5, 5);
// To make the fingerprint box wider, try:
- // ta_table.attach(fingerprint, 0, 2, row, row + 2, fill_and_expand, fill_and_expand, 20, 5);
+ ta_table.attach(fingerprint, 0, 2, row, row + 2, fill_and_expand, fill_and_expand, 20, 5);
}
else {
var services_table = new Table(card.services.size, 1, false);
services_table.set_row_spacings(1);
services_table.set_col_spacings(0);
- services_table.modify_bg(StateType.NORMAL, white);
+ set_bg_color(services_table);
var table_button_hbox = new HBox(false, 6);
table_button_hbox.pack_start(services_vscroll, true, true, 4);
// A table doesn't have a background color, so put it in an EventBox, and
// set the EventBox's background color instead.
EventBox table_bg = new EventBox();
- table_bg.modify_bg(StateType.NORMAL, white);
+ set_bg_color(table_bg);
table_bg.add(services_table);
services_vbox_alignment.add(table_bg);
internal CheckButton remember_identity_binding = null;
- private IdCard selected_idcard = null;
+ private IdCard selected_card = null;
private string import_directory = null;
set_default_size(WINDOW_WIDTH, WINDOW_HEIGHT);
build_ui();
setup_list_model();
- load_id_cards();
+ load_id_cards();
connect_signals();
+ report_duplicate_nais();
}
+ private void report_duplicate_nais() {
+ ArrayList<ArrayList<IdCard>> duplicates;
+ identities_manager.find_duplicate_nai_sets(out duplicates);
+ foreach (ArrayList<IdCard> list in duplicates) {
+ string message = _("The following identities use the same Network Access Identifier (NAI),\n'%s'.").printf(list.get(0).nai)
+ + _("\n\nDuplicate NAIs are not allowed. Please remove identities you don't need, or modify")
+ + _(" user ID or issuer fields so that they are no longer the same NAI.");
+
+ foreach (var card in list) {
+ message += "\n\nDisplay Name: '%s'\nServices:\n %s".printf(card.display_name, card.get_services_string(",\n "));
+ }
+ var msg_dialog = new Gtk.MessageDialog(this,
+ Gtk.DialogFlags.DESTROY_WITH_PARENT,
+ Gtk.MessageType.INFO,
+ Gtk.ButtonsType.OK,
+ message);
+ msg_dialog.run();
+ msg_dialog.destroy();
+ }
+ }
+
private void on_card_list_changed() {
logger.trace("on_card_list_changed");
load_id_cards();
{
logger.trace("add_id_card_widget: id_card.nai='%s'; selected nai='%s'"
.printf(id_card.nai,
- this.selected_idcard == null ? "[null selection]" : this.selected_idcard.nai));
+ this.selected_card == null ? "[null selection]" : this.selected_card.nai));
var id_card_widget = new IdCardWidget(id_card, this);
id_card_widget.expanded.connect(this.widget_selected_cb);
id_card_widget.collapsed.connect(this.widget_unselected_cb);
- if (this.selected_idcard != null && this.selected_idcard.nai == id_card.nai) {
+ if (this.selected_card != null && this.selected_card.nai == id_card.nai) {
logger.trace(@"add_id_card_widget: Expanding selected idcard widget");
id_card_widget.expand();
+
+ // After a card is added, modified, or deleted, we reload all the cards.
+ // (I'm not sure why, or if it's necessary to do this.) This means that the
+ // selected_card may now point to a card instance that's not in the current list.
+ // Hence the only way to carry the selection across reloads is to identify
+ // the selected card by its NAI. And hence we need to reset what our idea of the
+ // "selected card" is.
+ // There should be a better way to do this, especially since we're not great
+ // at preventing duplicate NAIs.
+ this.selected_card = id_card;
}
return id_card_widget;
}
{
logger.trace(@"widget_selected_cb: id_card_widget.id_card.display_name='$(id_card_widget.id_card.display_name)'");
- this.selected_idcard = id_card_widget.id_card;
+ this.selected_card = id_card_widget.id_card;
bool allow_removes = !id_card_widget.id_card.is_no_identity();
this.remove_button.set_sensitive(allow_removes);
this.edit_button.set_sensitive(true);
{
logger.trace(@"widget_unselected_cb: id_card_widget.id_card.display_name='$(id_card_widget.id_card.display_name)'");
- this.selected_idcard = null;
+ this.selected_card = null;
this.remove_button.set_sensitive(false);
this.edit_button.set_sensitive(false);
this.custom_vbox.receive_collapsed_event(id_card_widget);
switch (result) {
case ResponseType.OK:
this.identities_manager.update_card(update_id_card_data(dialog, card));
+
+ // Make sure we haven't created a duplicate NAI via this update.
+ report_duplicate_nais();
break;
default:
break;
private void remove_identity(IdCard id_card)
{
logger.trace(@"remove_identity: id_card.display_name='$(id_card.display_name)'");
- if (id_card != this.selected_idcard) {
- logger.error("remove_identity: id_card != this.selected_idcard!");
- }
- this.selected_idcard = null;
+ this.selected_card = null;
this.identities_manager.remove_card(id_card);
// Nothing is selected, so disable buttons
set_prompting_service(request.service);
remember_identity_binding.show();
- if (this.selected_idcard != null
- && this.custom_vbox.find_idcard_widget(this.selected_idcard) != null) {
+ if (this.custom_vbox.find_idcard_widget(this.selected_card) != null) {
// A widget is already selected, and has not been filtered out of the display via search
send_button.set_sensitive(true);
}
{
return_if_fail(this.selection_in_progress());
- if (!check_and_confirm_trust_anchor(id)) {
- // Allow user to pick again
- return;
- }
-
var request = this.request_queue.pop_head();
var identity = check_add_password(id, request, identities_manager);
send_button.set_sensitive(false);
remember_identity_binding.hide();
}
- private bool check_and_confirm_trust_anchor(IdCard id)
- {
- if (!id.trust_anchor.is_empty() && id.trust_anchor.get_anchor_type() == TrustAnchor.TrustAnchorType.SERVER_CERT) {
- if (!id.trust_anchor.user_verified) {
-
- bool ret = false;
- int result = ResponseType.CANCEL;
- var dialog = new TrustAnchorDialog(id, this);
- while (!dialog.complete)
- result = dialog.run();
-
- switch (result) {
- case ResponseType.OK:
- id.trust_anchor.user_verified = true;
- ret = true;
- break;
- default:
- break;
- }
-
- dialog.destroy();
- return ret;
- }
- }
- return true;
- }
-
private void on_about_action()
{
string copyright = "Copyright (c) 2011, %d JANET".printf(LATEST_EDIT_YEAR);
about.set_modal(true);
about.set_transient_for(this);
about.response.connect((a, b) => {about.destroy();});
- about.modify_bg(StateType.NORMAL, white);
+ set_bg_color(about);
about.run();
}
private void build_ui()
{
- // Note: On Debian7/Gtk+2, the menu bar remains gray. This doesn't happen on Debian8/Gtk+3.
- this.modify_bg(StateType.NORMAL, white);
+ set_bg_color(this);
create_ui_manager();
row++;
this.edit_button = new Button.with_label(_("Edit"));
- edit_button.clicked.connect((w) => {edit_identity_cb(this.selected_idcard);});
+ edit_button.clicked.connect((w) => {edit_identity_cb(this.selected_card);});
edit_button.set_sensitive(false);
top_table.attach(make_rigid(edit_button), num_cols - button_width, num_cols, row, row + 1, fill, fill, 0, 0);
row++;
this.remove_button = new Button.with_label(_("Remove"));
- remove_button.clicked.connect((w) => {remove_identity_cb(this.selected_idcard);});
+ remove_button.clicked.connect((w) => {remove_identity_cb(this.selected_card);});
remove_button.set_sensitive(false);
top_table.attach(make_rigid(remove_button), num_cols - button_width, num_cols, row, row + 1, fill, fill, 0, 0);
row++;
// push the send button down another row.
row++;
this.send_button = new Button.with_label(_("Send"));
- send_button.clicked.connect((w) => {send_identity_cb(this.selected_idcard);});
+ send_button.clicked.connect((w) => {send_identity_cb(this.selected_card);});
// send_button.set_visible(false);
send_button.set_sensitive(false);
top_table.attach(make_rigid(send_button), num_cols - button_width, num_cols, row, row + 1, fill, fill, 0, 0);
// quit_item.hide();
Gtk.MenuShell menushell = this.ui_manager.get_widget("/MenuBar") as Gtk.MenuShell;
- menushell.modify_bg(StateType.NORMAL, white);
osxApp.set_menu_bar(menushell);
osxApp.set_use_quartz_accelerators(true);
#else
var menubar = this.ui_manager.get_widget("/MenuBar");
main_vbox.pack_start(menubar, false, false, 0);
- menubar.modify_bg(StateType.NORMAL, white);
+ set_bg_color(menubar);
#endif
main_vbox.pack_start(top_table, true, true, 6);
logger.trace(@"import_identities_cb: Did not add or update '$(card.display_name)'");
}
}
- var msg_dialog = new Gtk.MessageDialog(this,
- Gtk.DialogFlags.DESTROY_WITH_PARENT,
- Gtk.MessageType.INFO,
- Gtk.ButtonsType.OK,
- _("Import completed. %d Identities were added or updated."),
- import_count);
- msg_dialog.run();
- msg_dialog.destroy();
+ if (import_count == 0) {
+ var msg_dialog = new Gtk.MessageDialog(this,
+ Gtk.DialogFlags.DESTROY_WITH_PARENT,
+ Gtk.MessageType.INFO,
+ Gtk.ButtonsType.OK,
+ _("Import completed. No identities were added or updated."));
+ msg_dialog.run();
+ msg_dialog.destroy();
+ }
}
dialog.destroy();
}
private MoonshotServer ipc_server;
private bool name_is_owned;
private bool show_requested;
+ public bool use_flat_file_store {public get; private set;}
#if OS_MACOS
public OSXApplication osxApp;
}
}
-#if LOG4VALA
+#if USE_LOG4VALA
// Call this from main() to ensure that the logger is initialized
internal IdentityManagerApp.dummy() {}
#endif
public IdentityManagerApp(bool headless, bool use_flat_file_store) {
use_flat_file_store |= UserForcesFlatFileStore();
+ this.use_flat_file_store = use_flat_file_store;
#if GNOME_KEYRING
bool keyring_available = (!use_flat_file_store) && GnomeKeyring.is_available();
public static int main(string[] args) {
-#if LOG4VALA
+#if USE_LOG4VALA
+ // Initialize the logger.
new IdentityManagerApp.dummy();
#endif
string server_cert = "";
string subject = "";
string subject_alt = "";
- bool user_verified = false;
string ta_datetime_added = "";
for (i = 0; i < entry.attributes.len; i++) {
var attribute = ((GnomeKeyring.Attribute *) entry.attributes.data)[i];
subject_alt = value;
} else if (attribute.name == "StorePassword") {
store_password = value;
- } else if (attribute.name == "TA_User_Verified") {
- user_verified = (value == "true");
} else if (attribute.name == "TA_DateTime_Added") {
ta_datetime_added = value;
}
}
- var ta = new TrustAnchor(ca_cert, server_cert, subject, subject_alt, user_verified);
+ var ta = new TrustAnchor(ca_cert, server_cert, subject, subject_alt);
if (ta_datetime_added != "") {
ta.set_datetime_added(ta_datetime_added);
}
id_card.password = entry.secret;
else
id_card.password = null;
+
id_card_list.add(id_card);
}
}
attributes.append_string("Server-Cert", id_card.trust_anchor.server_cert);
attributes.append_string("Subject", id_card.trust_anchor.subject);
attributes.append_string("Subject-Alt", id_card.trust_anchor.subject_alt);
- attributes.append_string("TA_User_Verified", id_card.trust_anchor.user_verified ? "true" : "false");
attributes.append_string("TA_DateTime_Added", id_card.trust_anchor.datetime_added);
attributes.append_string("StorePassword", id_card.store_password ? "yes" : "no");
string server_cert = key_file.get_string(identity, "ServerCert");
string subject = key_file.get_string(identity, "Subject");
string subject_alt = key_file.get_string(identity, "SubjectAlt");
- bool user_verified = get_bool_setting(identity, "TA_User_Verified", false, key_file);
- var ta = new TrustAnchor(ca_cert, server_cert, subject, subject_alt, user_verified);
+ var ta = new TrustAnchor(ca_cert, server_cert, subject, subject_alt);
string ta_datetime_added = get_string_setting(identity, "TA_DateTime_Added", "", key_file);
if (ta_datetime_added != "") {
ta.set_datetime_added(ta_datetime_added);
if (id_card.trust_anchor.datetime_added != "") {
key_file.set_string(id_card.display_name, "TA_DateTime_Added", id_card.trust_anchor.datetime_added);
}
- key_file.set_boolean(id_card.display_name, "TA_User_Verified", id_card.trust_anchor.user_verified);
logger.trace(@"store_id_cards: Stored '$(id_card.display_name)'");
}
{
this.set_title(_("Moonshot - Password"));
this.set_modal(true);
- this.modify_bg(StateType.NORMAL, white);
+ set_bg_color(this);
this.add_buttons(_("Cancel"), ResponseType.CANCEL,
_("Connect"), ResponseType.OK);
var content_area = this.get_content_area();
((Box) content_area).set_spacing(12);
- content_area.modify_bg(StateType.NORMAL, white);
+ set_bg_color(content_area);
Label dialog_label = new Label(_("Enter the password for ") + id_card.display_name);
dialog_label.set_alignment(0, 0);
var ta = new TrustAnchor(ta_ca_cert,
ta_server_cert,
ta_subject,
- ta_subject_alt,
- false);
+ ta_subject_alt);
// Set the datetime_added in moonshot-server.vala, since it doesn't get sent via IPC
card.set_trust_anchor_from_store(ta);
}
using Gee;
-#if IPC_DBUS
-
[DBus (name = "org.janet.Moonshot")]
public class MoonshotServer : Object {
idcard.store_password = true;
idcard.issuer = realm;
idcard.update_services(services);
- var ta = new TrustAnchor(ca_cert, server_cert, subject, subject_alt, false);
+ var ta = new TrustAnchor(ca_cert, server_cert, subject, subject_alt);
if (!ta.is_empty()) {
// We have to set the datetime_added here, because it isn't delivered via IPC.
}
return installed_cards;
}
-}
-
-
-#elif IPC_MSRPC
-
-using Rpc;
-using MoonshotRpcInterface;
-
-/* This class must be a singleton, because we use a global RPC
- * binding handle. I cannot picture a situation where more than
- * one instance of the same interface would be needed so this
- * shouldn't be a problem.
- *
- * Shutdown is automatically done by the RPC runtime when the
- * process ends
- */
-public class MoonshotServer : Object {
- private static IdentityManagerApp parent_app;
-
- private static MoonshotServer instance = null;
-
- public static void start(IdentityManagerApp app)
- {
- parent_app = app;
- Rpc.server_start(MoonshotRpcInterface.spec, "/org/janet/Moonshot", Rpc.Flags.PER_USER);
- }
-
- public static MoonshotServer get_instance()
- {
- if (instance == null)
- instance = new MoonshotServer();
- return instance;
- }
- [CCode (cname = "moonshot_get_identity_rpc")]
- public static void get_identity(Rpc.AsyncCall call,
- string nai,
- string password,
- string service,
- ref string nai_out,
- ref string password_out,
- ref string server_certificate_hash,
- ref string ca_certificate,
- ref string subject_name_constraint,
- ref string subject_alt_name_constraint)
+ public async bool confirm_ca_certificate(string nai,
+ string realm,
+ string ca_hash,
+ out int confirmed)
{
- logger.trace("(static) get_identity");
-
- bool result = false;
-
- var request = new IdentityRequest(parent_app,
- nai,
- password,
- service);
-
- // Pass execution to the main loop and block the RPC thread
- request.mutex = new Mutex();
- request.cond = new Cond();
- request.set_callback(return_identity_cb);
-
- request.mutex.lock();
- Idle.add(request.execute);
-
- while (request.complete == false)
- request.cond.wait(request.mutex);
-
- nai_out = "";
- password_out = "";
- server_certificate_hash = "";
- ca_certificate = "";
- subject_name_constraint = "";
- subject_alt_name_constraint = "";
-
- var id_card = request.id_card;
-
- if (id_card != null) {
- // The strings are freed by the RPC runtime
- nai_out = id_card.nai;
- password_out = id_card.password;
- server_certificate_hash = id_card.trust_anchor.server_cert;
- ca_certificate = id_card.trust_anchor.ca_cert;
- subject_name_constraint = id_card.trust_anchor.subject;
- subject_alt_name_constraint = id_card.trust_anchor.subject_alt;
-
- return_if_fail(nai_out != null);
- return_if_fail(password_out != null);
- return_if_fail(server_certificate_hash != null);
- return_if_fail(ca_certificate != null);
- return_if_fail(subject_name_constraint != null);
- return_if_fail(subject_alt_name_constraint != null);
-
- result = true;
- }
-
- // The outputs must be set before this function is called. For this
- // reason they are 'ref' not 'out' parameters - Vala assigns to the
- // 'out' parameters only at the end of the function, which is too
- // late.
- call.return(&result);
-
- request.cond.signal();
- request.mutex.unlock();
- }
-
- [CCode (cname = "moonshot_get_default_identity_rpc")]
- public static void get_default_identity(Rpc.AsyncCall call,
- ref string nai_out,
- ref string password_out,
- ref string server_certificate_hash,
- ref string ca_certificate,
- ref string subject_name_constraint,
- ref string subject_alt_name_constraint)
- {
- logger.trace("(static) get_default_identity");
-
- bool result;
-
- var request = new IdentityRequest.default(parent_app);
- request.mutex = new Mutex();
- request.cond = new Cond();
- request.set_callback(return_identity_cb);
+ logger.trace(@"MoonshotServer.confirm_ca_certificate: nai='$nai'; realm='$realm'; ca_hash='$ca_hash'");
- request.mutex.lock();
- Idle.add(request.execute);
-
- while (request.complete == false)
- request.cond.wait(request.mutex);
-
- nai_out = "";
- password_out = "";
- server_certificate_hash = "";
- ca_certificate = "";
- subject_name_constraint = "";
- subject_alt_name_constraint = "";
-
- if (request.id_card != null)
- {
- nai_out = request.id_card.nai;
- password_out = request.id_card.password;
- server_certificate_hash = "certificate";
-
- return_if_fail(nai_out != null);
- return_if_fail(password_out != null);
- return_if_fail(server_certificate_hash != null);
- return_if_fail(ca_certificate != null);
- return_if_fail(subject_name_constraint != null);
- return_if_fail(subject_alt_name_constraint != null);
-
- result = true;
- }
- else
- {
- result = false;
- }
-
- call.return(&result);
-
- request.cond.signal();
- request.mutex.unlock();
- }
-
- // Called from the main loop thread when an identity has
- // been selected
- static void return_identity_cb(IdentityRequest request) {
- // Notify the RPC thread that the request is complete
- request.mutex.lock();
- request.cond.signal();
-
- // Block the main loop until the RPC call has returned
- // to avoid any races
- request.cond.wait(request.mutex);
- request.mutex.unlock();
- }
-
- [CCode (cname = "moonshot_install_id_card_rpc")]
- public static bool install_id_card(string display_name,
- string user_name,
- string password,
- string realm,
- string[] rules_patterns,
- string[] rules_always_confirm,
- string[] services,
- string ca_cert,
- string subject,
- string subject_alt,
- string server_cert,
- bool force_flat_file_store)
- {
- logger.trace("(static) install_id_card");
- IdCard idcard = new IdCard();
-
- bool success = false;
- Mutex mutex = new Mutex();
- Cond cond = new Cond();
-
- idcard.display_name = display_name;
- idcard.username = user_name;
- idcard.password = password;
- idcard.issuer = realm;
- idcard.services = services;
- idcard.trust_anchor.ca_cert = ca_cert;
- idcard.trust_anchor.subject = subject;
- idcard.trust_anchor.subject_alt = subject_alt;
- idcard.trust_anchor.server_cert = server_cert;
-
- if (rules_patterns.length == rules_always_confirm.length)
- {
- idcard.rules = new Rule[rules_patterns.length];
-
- for (int i = 0; i < idcard.rules.length; i++)
- {
- idcard.rules[i].pattern = rules_patterns[i];
- idcard.rules[i].always_confirm = rules_always_confirm[i];
- }
- }
-
- mutex.lock();
-
- ArrayList<IdCard>? old_duplicates = null;
- // Defer addition to the main loop thread.
- Idle.add(() => {
- mutex.lock();
- success = parent_app.add_identity(idcard, force_flat_file_store, out old_duplicates);
- foreach (IdCard id_card in old_duplicates) {
- stdout.printf("removing duplicate id for '%s'\n", new_card.nai);
- }
- cond.signal();
- mutex.unlock();
- return false;
- });
-
- cond.wait(mutex);
- mutex.unlock();
+ var request = new TrustAnchorConfirmationRequest(parent_app, nai, realm, ca_hash);
+ request.set_callback((TrustAnchorConfirmationRequest) => confirm_ca_certificate.callback());
+ request.execute();
+ yield;
- return success;
+ confirmed = (request.confirmed ? 1 : 0);
+ logger.trace(@"MoonshotServer.confirm_ca_certificate: confirmed=$confirmed");
+ return true;
}
-
}
-
-
-#endif
--- /dev/null
+/*
+ * Copyright (c) 2011-2016, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+*/
+
+using Gee;
+
+
+using Rpc;
+using MoonshotRpcInterface;
+
+/* This class must be a singleton, because we use a global RPC
+ * binding handle. I cannot picture a situation where more than
+ * one instance of the same interface would be needed so this
+ * shouldn't be a problem.
+ *
+ * Shutdown is automatically done by the RPC runtime when the
+ * process ends
+ */
+public class MoonshotServer : Object {
+ private static IdentityManagerApp parent_app;
+
+ private static MoonshotServer instance = null;
+
+ public static void start(IdentityManagerApp app)
+ {
+ parent_app = app;
+ Rpc.server_start(MoonshotRpcInterface.spec, "/org/janet/Moonshot", Rpc.Flags.PER_USER);
+ }
+
+ public static MoonshotServer get_instance()
+ {
+ if (instance == null)
+ instance = new MoonshotServer();
+ return instance;
+ }
+
+ [CCode (cname = "moonshot_get_identity_rpc")]
+ public static void get_identity(Rpc.AsyncCall call,
+ string nai,
+ string password,
+ string service,
+ ref string nai_out,
+ ref string password_out,
+ ref string server_certificate_hash,
+ ref string ca_certificate,
+ ref string subject_name_constraint,
+ ref string subject_alt_name_constraint)
+ {
+ logger.trace("(static) get_identity");
+
+ bool result = false;
+
+ var request = new IdentityRequest(parent_app,
+ nai,
+ password,
+ service);
+
+ // Pass execution to the main loop and block the RPC thread
+ request.mutex = new Mutex();
+ request.cond = new Cond();
+ request.set_callback(return_identity_cb);
+
+ request.mutex.lock();
+ Idle.add(request.execute);
+
+ while (request.complete == false)
+ request.cond.wait(request.mutex);
+
+ nai_out = "";
+ password_out = "";
+ server_certificate_hash = "";
+ ca_certificate = "";
+ subject_name_constraint = "";
+ subject_alt_name_constraint = "";
+
+ var id_card = request.id_card;
+
+ if (id_card != null) {
+ // The strings are freed by the RPC runtime
+ nai_out = id_card.nai;
+ password_out = id_card.password;
+ server_certificate_hash = id_card.trust_anchor.server_cert;
+ ca_certificate = id_card.trust_anchor.ca_cert;
+ subject_name_constraint = id_card.trust_anchor.subject;
+ subject_alt_name_constraint = id_card.trust_anchor.subject_alt;
+
+ return_if_fail(nai_out != null);
+ return_if_fail(password_out != null);
+ return_if_fail(server_certificate_hash != null);
+ return_if_fail(ca_certificate != null);
+ return_if_fail(subject_name_constraint != null);
+ return_if_fail(subject_alt_name_constraint != null);
+
+ result = true;
+ }
+
+ // The outputs must be set before this function is called. For this
+ // reason they are 'ref' not 'out' parameters - Vala assigns to the
+ // 'out' parameters only at the end of the function, which is too
+ // late.
+ call.return(&result);
+
+ request.cond.signal();
+ request.mutex.unlock();
+ }
+
+ [CCode (cname = "moonshot_get_default_identity_rpc")]
+ public static void get_default_identity(Rpc.AsyncCall call,
+ ref string nai_out,
+ ref string password_out,
+ ref string server_certificate_hash,
+ ref string ca_certificate,
+ ref string subject_name_constraint,
+ ref string subject_alt_name_constraint)
+ {
+ logger.trace("(static) get_default_identity");
+
+ bool result;
+
+ var request = new IdentityRequest.default(parent_app);
+ request.mutex = new Mutex();
+ request.cond = new Cond();
+ request.set_callback(return_identity_cb);
+
+ request.mutex.lock();
+ Idle.add(request.execute);
+
+ while (request.complete == false)
+ request.cond.wait(request.mutex);
+
+ nai_out = "";
+ password_out = "";
+ server_certificate_hash = "";
+ ca_certificate = "";
+ subject_name_constraint = "";
+ subject_alt_name_constraint = "";
+
+ if (request.id_card != null)
+ {
+ nai_out = request.id_card.nai;
+ password_out = request.id_card.password;
+ server_certificate_hash = "certificate";
+
+ return_if_fail(nai_out != null);
+ return_if_fail(password_out != null);
+ return_if_fail(server_certificate_hash != null);
+ return_if_fail(ca_certificate != null);
+ return_if_fail(subject_name_constraint != null);
+ return_if_fail(subject_alt_name_constraint != null);
+
+ result = true;
+ }
+ else
+ {
+ result = false;
+ }
+
+ call.return(&result);
+
+ request.cond.signal();
+ request.mutex.unlock();
+ }
+
+ // Called from the main loop thread when an identity has
+ // been selected
+ static void return_identity_cb(IdentityRequest request) {
+ // Notify the RPC thread that the request is complete
+ request.mutex.lock();
+ request.cond.signal();
+
+ // Block the main loop until the RPC call has returned
+ // to avoid any races
+ request.cond.wait(request.mutex);
+ request.mutex.unlock();
+ }
+
+ [CCode (cname = "moonshot_install_id_card_rpc")]
+ public static bool install_id_card(string display_name,
+ string user_name,
+ string password,
+ string realm,
+ string[] rules_patterns,
+ string[] rules_always_confirm,
+ string[] services,
+ string ca_cert,
+ string subject,
+ string subject_alt,
+ string server_cert,
+ bool force_flat_file_store)
+ {
+ logger.trace("(static) install_id_card");
+ IdCard idcard = new IdCard();
+
+ bool success = false;
+ Mutex mutex = new Mutex();
+ Cond cond = new Cond();
+
+ idcard.display_name = display_name;
+ idcard.username = user_name;
+ idcard.password = password;
+ idcard.issuer = realm;
+ idcard.services = services;
+ idcard.trust_anchor.ca_cert = ca_cert;
+ idcard.trust_anchor.subject = subject;
+ idcard.trust_anchor.subject_alt = subject_alt;
+ idcard.trust_anchor.server_cert = server_cert;
+
+ if (rules_patterns.length == rules_always_confirm.length)
+ {
+ idcard.rules = new Rule[rules_patterns.length];
+
+ for (int i = 0; i < idcard.rules.length; i++)
+ {
+ idcard.rules[i].pattern = rules_patterns[i];
+ idcard.rules[i].always_confirm = rules_always_confirm[i];
+ }
+ }
+
+ mutex.lock();
+
+ ArrayList<IdCard>? old_duplicates = null;
+ // Defer addition to the main loop thread.
+ Idle.add(() => {
+ mutex.lock();
+ success = parent_app.add_identity(idcard, force_flat_file_store, out old_duplicates);
+ foreach (IdCard id_card in old_duplicates) {
+ stdout.printf("removing duplicate id for '%s'\n", new_card.nai);
+ }
+ cond.signal();
+ mutex.unlock();
+ return false;
+ });
+
+ cond.wait(mutex);
+ mutex.unlock();
+
+ return success;
+ }
+}
*/
using Gtk;
+public delegate void TrustAnchorConfirmationCallback(TrustAnchorConfirmationRequest request);
+
+public class TrustAnchorConfirmationRequest : GLib.Object {
+ static MoonshotLogger logger = get_logger("TrustAnchorConfirmationRequest");
+
+ IdentityManagerApp parent_app;
+ string userid;
+ string realm;
+ string ca_hash;
+ public bool confirmed = false;
+
+ TrustAnchorConfirmationCallback callback = null;
+
+ public TrustAnchorConfirmationRequest(IdentityManagerApp parent_app,
+ string userid,
+ string realm,
+ string ca_hash)
+ {
+ this.parent_app = parent_app;
+ this.userid = userid;
+ this.realm = realm;
+ this.ca_hash = ca_hash;
+ }
+
+ public void set_callback(owned TrustAnchorConfirmationCallback cb)
+ {
+// #if VALA_0_12
+ this.callback = ((owned) cb);
+// #else
+// this.callback = ((IdCard) => cb(IdCard));
+// #endif
+ }
+
+ public bool execute() {
+
+ string nai = userid + "@" + realm;
+ IdCard? card = parent_app.model.find_id_card(nai, parent_app.use_flat_file_store);
+ if (card == null) {
+ logger.warn(@"execute: Could not find ID card for NAI $nai; returning false.");
+ return_confirmation(false);
+ return false;
+ }
+
+ if (!(card.trust_anchor.is_empty() || card.trust_anchor.get_anchor_type() == TrustAnchor.TrustAnchorType.SERVER_CERT)) {
+ logger.warn(@"execute: Trust anchor type for NAI $nai is not empty or SERVER_CERT; returning true.");
+ return_confirmation(true);
+ return false;
+ }
+
+ if (card.trust_anchor.server_cert == ca_hash) {
+ logger.trace(@"execute: Fingerprint for $nai matches stored value; returning true.");
+ return_confirmation(true);
+ return false;
+ }
+
+ var dialog = new TrustAnchorDialog(userid, realm, ca_hash);
+ var response = dialog.run();
+ dialog.destroy();
+ bool is_confirmed = (response == ResponseType.OK);
+
+ if (is_confirmed) {
+ logger.trace(@"execute: Fingerprint confirmed; updating stored value.");
+
+ card.trust_anchor.update_server_fingerprint(ca_hash);
+ parent_app.model.update_card(card);
+ }
+
+ return_confirmation(is_confirmed);
+
+ /* This function works as a GSourceFunc, so it can be passed to
+ * the main loop from other threads
+ */
+ return false;
+ }
+
+ private void return_confirmation(bool confirmed) {
+ return_if_fail(callback != null);
+
+ this.confirmed = confirmed;
+ logger.trace(@"return_confirmation: confirmed=$confirmed");
+
+ // Send back the confirmation (we can't directly run the
+ // callback because we may be being called from a 'yield')
+ GLib.Idle.add(
+ () => {
+ logger.trace("return_confirmation[Idle handler]: invoking callback");
+ callback(this);
+ return false;
+ }
+ );
+ }
+}
+
+
+
class TrustAnchorDialog : Dialog
{
private static Gdk.Color white = make_color(65535, 65535, 65535);
public bool complete = false;
- public TrustAnchorDialog(IdCard idcard, Window parent)
+ public TrustAnchorDialog(string userid,
+ string realm,
+ string ca_hash)
{
this.set_title(_("Trust Anchor"));
this.set_modal(true);
- this.set_transient_for(parent);
- this.modify_bg(StateType.NORMAL, white);
+// this.set_transient_for(parent);
+ set_bg_color(this);
this.add_buttons(_("Cancel"), ResponseType.CANCEL,
_("Confirm"), ResponseType.OK);
var content_area = this.get_content_area();
((Box) content_area).set_spacing(12);
- content_area.modify_bg(StateType.NORMAL, white);
+ set_bg_color(content_area);
Label dialog_label = new Label("");
dialog_label.set_alignment(0, 0);
dialog_label.set_line_wrap(true);
dialog_label.set_width_chars(60);
- var user_label = new Label(_("Username: ") + idcard.username);
+ var user_label = new Label(_("Username: ") + userid);
user_label.set_alignment(0, 0.5f);
- var realm_label = new Label(_("Realm: ") + idcard.issuer);
+ var realm_label = new Label(_("Realm: ") + realm);
realm_label.set_alignment(0, 0.5f);
Label confirm_label = new Label(_("Please confirm that this is the correct trust anchor."));
confirm_label.set_alignment(0, 0.5f);
- var trust_anchor_display = make_ta_fingerprint_widget(idcard.trust_anchor);
+ var trust_anchor_display = make_ta_fingerprint_widget(ca_hash);
var vbox = new VBox(false, 0);
vbox.set_border_width(6);
}
-internal Widget make_ta_fingerprint_widget(TrustAnchor trust_anchor)
+internal Widget make_ta_fingerprint_widget(string server_cert)
{
var fingerprint_label = new Label(_("SHA-256 fingerprint:"));
fingerprint_label.set_alignment(0, 0.5f);
fingerprint.set_editable(false);
fingerprint.set_left_margin(3);
var buffer = fingerprint.get_buffer();
- buffer.set_text(colonize(trust_anchor.server_cert, 16), -1);
+ buffer.set_text(colonize(server_cert, 16), -1);
fingerprint.wrap_mode = Gtk.WrapMode.WORD_CHAR;
set_atk_relation(fingerprint_label, fingerprint, Atk.RelationType.LABEL_FOR);
var fingerprint_width_constraint = new ScrolledWindow(null, null);
fingerprint_width_constraint.set_policy(PolicyType.NEVER, PolicyType.NEVER);
fingerprint_width_constraint.set_shadow_type(ShadowType.IN);
- fingerprint_width_constraint.set_size_request(300, 60);
+ fingerprint_width_constraint.set_size_request(360, 60);
fingerprint_width_constraint.add_with_viewport(fingerprint);
var vbox = new VBox(false, 0);
}
return result;
}
+
+static Gdk.Color white;
+static void set_bg_color(Widget w)
+{
+#if OS_WIN32
+
+ if (white == null) {
+ white = make_color(65535, 65535, 65535);
+ }
+
+ w.modify_bg(StateType.NORMAL, white);
+
+#endif
+}
// dialog.set_modal(true);
dialog.set_title(_("Warning"));
- dialog.modify_bg(StateType.NORMAL, white);
+ set_bg_color(dialog);
// ((Box) content_area).set_spacing(12);
- content_area.modify_bg(StateType.NORMAL, white);
+ set_bg_color(content_area);
content_area.show_all();
--- /dev/null
+<!-- See https://bugs.launchpad.net/moonshot-ui/+bug/1430980, including comments -->
+
+<identities>
+
+ <identity>
+ <display-name>Not No Identity</display-name>
+ <user>someone</user>
+ <password></password>
+ <realm>painless-security.com</realm>
+ <services>
+ <service>something/painless-security.com</service>
+ <service>somethingelse/painless-security.com</service>
+ </services>
+ </identity>
+
+ <identity>
+ <display-name>No Identity</display-name>
+ <services>
+ <service>a_service/painless-security.com</service>
+ <service>another_service/painless-security.com</service>
+ </services>
+ </identity>
+
+</identities>
--- /dev/null
+<identities>
+ <identity>
+ <display-name>No Trust Anchor</display-name>
+ <user>user5</user>
+ <password></password>
+ <realm>painless-security.com</realm>
+ <services>
+ </services>
+ </identity>
+
+ <identity>
+ <display-name>Bad CA Certificate</display-name>
+ <user>user1</user>
+ <password></password>
+ <realm>painless-security.com</realm>
+ <services>
+ </services>
+ <selection-rules>
+ </selection-rules>
+ <trust-anchor>
+ <!-- PEM encoded, minus header and footer -->
+ <ca-cert>MIIE5DCCA8ygAwIBAgIJAOz4PYh7hLBrMA0GCSqGSIb3DQEBBQUAMIGTMQswCQYD
+VQQGEwJGUjEPMA0GA1UECBMGUmFkaXVzMRIwEAYDVQQHEwlTb21ld2hlcmUxFTAT
+BgNVBAoTDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBs
+ZS5vcmcxJjAkBgNVBAMTHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4X
+DTE2MTAwNDE3MDYwMFoXDTE2MTIwMzE3MDYwMFowgZMxCzAJBgNVBAYTAkZSMQ8w
+DQYDVQQIEwZSYWRpdXMxEjAQBgNVBAcTCVNvbWV3aGVyZTEVMBMGA1UEChMMRXhh
+bXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLm9yZzEmMCQG
+A1UEAxMdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQC3wTX5gGxa/Ge1RN4ZDx67WIeFxmKv6ZkS0c1p
+H2BS7RDGmBrWMG+RMX/kUdSNL1tarnbHknPYzKSdoTsM7bWLQpj1fV8nI4ZAF4Tp
+QG8jQHFmpTfHPjDv+E6wEfilyfXRDpym8ITQfLXTn85zvK82F+153Aqh+BrCyOvJ
+gANAoulArphg0UH6eyBuD+dezqXsinIMXfXZheTXi/TL3oSGjYkwF//WZUpmK5Kx
+w1NupFMjjCJzWf0MtDgG4Gl83JJMzoy/pSKvzWeglvaI8tt64iUkbKNstJT9C0G2
+y+fVM9aVeRAQ+1O1LRaKgqhQMTrs/LPQNUapRKGvkwXlCR6lAgMBAAGjggE3MIIB
+MzAdBgNVHQ4EFgQUMin4EfnT51ecs4f1KjpamdjQUDcwgcgGA1UdIwSBwDCBvYAU
+Min4EfnT51ecs4f1KjpamdjQUDehgZmkgZYwgZMxCzAJBgNVBAYTAkZSMQ8wDQYD
+VQQIEwZSYWRpdXMxEjAQBgNVBAcTCVNvbWV3aGVyZTEVMBMGA1UEChMMRXhhbXBs
+ZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLm9yZzEmMCQGA1UE
+AxMdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCCQDs+D2Ie4SwazAPBgNV
+HRMBAf8EBTADAQH/MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly93d3cuZXhhbXBs
+ZS5vcmcvZXhhbXBsZV9jYS5jcmwwDQYJKoZIhvcNAQEFBQADggEBAHzr/erMvZ76
+7FHpf5H3G/TL57k5POnDlTnolXmQdK2eaq0xLhaPuilvNa3txGGI0iBJAD20K5ss
+2o7ULHaAeuNAZ5+zuRx2xZrtLV3FQkugQZb70K/lECf3uCX4S/SqTeOo5VfPjaTM
+6MMgU9Tmvo9a1q7xHzm2yEqzhCbP7dZ4BmUPw9QIkqbirlcQ2GgxOah5m94e2ETf
+4SOBwM+5Lg+CAaCoIC0gpX2R3H+n4edslmiCoyU1r/Q6RQXiyWPdI6jjln08Jdt5
+0/rSpmhObSL0L7/z53+ka7jqW1ZxizVKYJiEIH9Y9Aw/vgf5nhnTgfTPfyPESyCO
+fi186fRC+Zs=</ca-cert>
+ <subject>Painless Security Server Certificate</subject>
+ <!-- Or alternatively -->
+ <server-cert></server-cert>
+ </trust-anchor>
+ </identity>
+ <identity>
+ <display-name>Good CA Certificate</display-name>
+ <user>user2</user>
+ <password></password>
+ <realm>painless-security.com</realm>
+ <services>
+ </services>
+ <selection-rules>
+ </selection-rules>
+ <trust-anchor>
+ <ca-cert>
+ <!-- DER format, base64-encoded -->
+MIIE9jCCA96gAwIBAgIJANI5K4+KXvQyMA0GCSqGSIb3DQEBBQUAMIGaMQswCQYD
+VQQGEwJVUzELMAkGA1UECBMCTUExDzANBgNVBAcTBk1hbGRlbjEaMBgGA1UEChMR
+UGFpbmxlc3MgU2VjdXJpdHkxLzAtBgkqhkiG9w0BCQEWIHBvc3RtYXN0ZXJAcGFp
+bmxlc3Mtc2VjdXJpdHkuY29tMSAwHgYDVQQDExdQYWlubGVzcyBTZWN1cml0eSwg
+SW5jLjAeFw0xNjA4MzAxOTU4MjlaFw0xOTEyMTMxOTU4MjlaMIGaMQswCQYDVQQG
+EwJVUzELMAkGA1UECBMCTUExDzANBgNVBAcTBk1hbGRlbjEaMBgGA1UEChMRUGFp
+bmxlc3MgU2VjdXJpdHkxLzAtBgkqhkiG9w0BCQEWIHBvc3RtYXN0ZXJAcGFpbmxl
+c3Mtc2VjdXJpdHkuY29tMSAwHgYDVQQDExdQYWlubGVzcyBTZWN1cml0eSwgSW5j
+LjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ6tW6x+aO4n7VJu5W55
+DeNKn7+89oaaTgSRs6jg3C+RpTmXugPonh9+YRbuWpSNeru2eWGFNYFs01OjaDUw
+CxPcFDgF3xP/wAyCsI7WUgmkz8991PUGo9RxVbkDxMePHNaLGQVNz/+EJgK/Ycfy
+jYvenb/BGvcBmMftk2HsHio65ZsHsGMfW2Wcg/ehvKeDRZ3WR1ujhkzIFWdgdH3E
+u/yI2pHEfxQQ3PuYcQz43YZyIwhwzwnQG8qTK2jWkMF+wzRKRYfLdRD8nUUingvu
+IbngXLs71JqQHmbXzw1WTJClXtfF6R2VZuZ6PT8ZK1bDFPvTgnkUcAk70H+VnDM5
+K48CAwEAAaOCATswggE3MB0GA1UdDgQWBBQoFRKLJrZvkNmqvw8DNuTLPyru/DCB
+zwYDVR0jBIHHMIHEgBQoFRKLJrZvkNmqvw8DNuTLPyru/KGBoKSBnTCBmjELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgTAk1BMQ8wDQYDVQQHEwZNYWxkZW4xGjAYBgNVBAoT
+EVBhaW5sZXNzIFNlY3VyaXR5MS8wLQYJKoZIhvcNAQkBFiBwb3N0bWFzdGVyQHBh
+aW5sZXNzLXNlY3VyaXR5LmNvbTEgMB4GA1UEAxMXUGFpbmxlc3MgU2VjdXJpdHks
+IEluYy6CCQDSOSuPil70MjAMBgNVHRMEBTADAQH/MDYGA1UdHwQvMC0wK6ApoCeG
+JWh0dHA6Ly93d3cuZXhhbXBsZS5jb20vZXhhbXBsZV9jYS5jcmwwDQYJKoZIhvcN
+AQEFBQADggEBAIN38UOXvwd89+a89V+/rjeN8JfpcjafLf0c2I3nex9OxBWji5bf
+cWTNfm1t9GpS4HhVT2tl5xdxyW5UrE9Q+oFadN0LxtRPbGU+Gvt4pVo8Pst6/2P8
+PA3/OA1UchIpZR6EWQQsws4esNLLwDbj48MkQdVCjpp1cVpFVmJUzYYFD9h9EMK2
+kxpGf5wfp9LI2A5/qACNQPBDfRsR+dcNBsBbmD1LulqputUPuKPXnVbHWL28VZUY
+PITHl2Ndbmk6znSu7ILef3CGyeXqTTj+Jo+5AQz3sneko6oMn8PqfRj1h0uUyykT
+lavp3iTNstQs/rdqdI+lPYMokDKXRSD3pK8=
+</ca-cert>
+ <subject>Painless Security Server Certificate</subject>
+ </trust-anchor>
+ </identity>
+ <identity>
+ <display-name>Good Fingerprint</display-name>
+ <user>user3</user>
+ <password></password>
+ <realm>painless-security.com</realm>
+ <services>
+ </services>
+ <trust-anchor>
+ <server-cert>F2FCC5FAD4CCB7A7236A8AEEF5E94E0C0FB27BEC29DE0AE03C5B455D08D4DE77</server-cert>
+ </trust-anchor>
+ </identity>
+ <identity>
+ <display-name>Bad Fingerprint</display-name>
+ <user>user4</user>
+ <password></password>
+ <realm>painless-security.com</realm>
+ <services>
+ </services>
+ <trust-anchor>
+ <server-cert>4242424242424242424242424242424242424242424242424242424242424242</server-cert>
+ </trust-anchor>
+ </identity>
+
+</identities>
</selection-rules>
<trust-anchor>
<ca-cert>
- <!-- DER format, base64-encoded -->MIIE9jCCA96gAwIBAgIJAJ6SVDCP6o2nMA0GCSqGSIb3DQEBBQUAMIGaMQswCQYDVQQGEwJVUzEL
-MAkGA1UECBMCTUExDzANBgNVBAcTBk1hbGRlbjEaMBgGA1UEChMRUGFpbmxlc3MgU2VjdXJpdHkx
-LzAtBgkqhkiG9w0BCQEWIHBvc3RtYXN0ZXJAcGFpbmxlc3Mtc2VjdXJpdHkuY29tMSAwHgYDVQQD
-ExdQYWlubGVzcyBTZWN1cml0eSwgSW5jLjAeFw0xNjA4MDExNjIxMDVaFw0xOTExMTQxNjIxMDVa
-MIGaMQswCQYDVQQGEwJVUzELMAkGA1UECBMCTUExDzANBgNVBAcTBk1hbGRlbjEaMBgGA1UEChMR
-UGFpbmxlc3MgU2VjdXJpdHkxLzAtBgkqhkiG9w0BCQEWIHBvc3RtYXN0ZXJAcGFpbmxlc3Mtc2Vj
-dXJpdHkuY29tMSAwHgYDVQQDExdQYWlubGVzcyBTZWN1cml0eSwgSW5jLjCCASIwDQYJKoZIhvcN
-AQEBBQADggEPADCCAQoCggEBAKPiSkw1y6zMJFjnoPjd5Bh9EA1NhQcoNxJAtgYEJtpH9a2tfjnX
-XncXpbIMIfMgv2VKRAxvKb+knCfSCRtUPM9i998+ZhJY9o6SSFomlMvdaClauPvBhQvQMmJmp1WI
-NgMUHPpzsGlj04kkl7jwiK/oDxp1becikKc10Gr9W03aEJtOaiSqC45zeIgnz9GoQ2tJvz2DDBcd
-daaT1mSVn/lk4ahPC4XaJ08Jn1L6XkVVyDGD38Rwg7r1SFI7ByBFvvQh93Fa48Z7ik0I8s48U1eu
-Hak2gSJ4zfzLndvGy05qMjhRTlxQu+Rt1g7CS3CLcJqqYzWNrEJWpD8Wn7iAMIUCAwEAAaOCATsw
-ggE3MB0GA1UdDgQWBBR1qlvY7r2DqhHu5s+sCUPeqBcQuzCBzwYDVR0jBIHHMIHEgBR1qlvY7r2D
-qhHu5s+sCUPeqBcQu6GBoKSBnTCBmjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMQ8wDQYDVQQH
-EwZNYWxkZW4xGjAYBgNVBAoTEVBhaW5sZXNzIFNlY3VyaXR5MS8wLQYJKoZIhvcNAQkBFiBwb3N0
-bWFzdGVyQHBhaW5sZXNzLXNlY3VyaXR5LmNvbTEgMB4GA1UEAxMXUGFpbmxlc3MgU2VjdXJpdHks
-IEluYy6CCQCeklQwj+qNpzAMBgNVHRMEBTADAQH/MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly93
-d3cuZXhhbXBsZS5jb20vZXhhbXBsZV9jYS5jcmwwDQYJKoZIhvcNAQEFBQADggEBAB6J5Zxvq96S
-dIsfEajqU+pANBiA2VTZCpxfIMAKz8KfyzWzFvCM8epvYDliyOjw1zR9cYxhQqOcbPHrjLXheVvC
-ePd3jCUOv+tt1Nw2gS2DiMuq37DOBZOTlPJ3m2NnvJVO3NjB2I+Pk9v3YlG6mkiVc9dNWgO20SqT
-2Y+KvHqA5Of8Cb/suIBftctvGpIyEnqSmU7KB0nhIWe65Bsu60hjHHfX1qhJE7qGKbqNaHujssQ/
-SBXJg7HUhtywv8z3TFoYW0MoBpKGM2Ojc9kQ8f0rYvUKTiD1UfjQoll/Io5xwKy7FXtnmusuCxXe
-WkqDtw0clWg6vkf5Tb9v/JQ2PW0=
+ <!-- DER format, base64-encoded -->
+MIIE9jCCA96gAwIBAgIJANI5K4+KXvQyMA0GCSqGSIb3DQEBBQUAMIGaMQswCQYD
+VQQGEwJVUzELMAkGA1UECBMCTUExDzANBgNVBAcTBk1hbGRlbjEaMBgGA1UEChMR
+UGFpbmxlc3MgU2VjdXJpdHkxLzAtBgkqhkiG9w0BCQEWIHBvc3RtYXN0ZXJAcGFp
+bmxlc3Mtc2VjdXJpdHkuY29tMSAwHgYDVQQDExdQYWlubGVzcyBTZWN1cml0eSwg
+SW5jLjAeFw0xNjA4MzAxOTU4MjlaFw0xOTEyMTMxOTU4MjlaMIGaMQswCQYDVQQG
+EwJVUzELMAkGA1UECBMCTUExDzANBgNVBAcTBk1hbGRlbjEaMBgGA1UEChMRUGFp
+bmxlc3MgU2VjdXJpdHkxLzAtBgkqhkiG9w0BCQEWIHBvc3RtYXN0ZXJAcGFpbmxl
+c3Mtc2VjdXJpdHkuY29tMSAwHgYDVQQDExdQYWlubGVzcyBTZWN1cml0eSwgSW5j
+LjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ6tW6x+aO4n7VJu5W55
+DeNKn7+89oaaTgSRs6jg3C+RpTmXugPonh9+YRbuWpSNeru2eWGFNYFs01OjaDUw
+CxPcFDgF3xP/wAyCsI7WUgmkz8991PUGo9RxVbkDxMePHNaLGQVNz/+EJgK/Ycfy
+jYvenb/BGvcBmMftk2HsHio65ZsHsGMfW2Wcg/ehvKeDRZ3WR1ujhkzIFWdgdH3E
+u/yI2pHEfxQQ3PuYcQz43YZyIwhwzwnQG8qTK2jWkMF+wzRKRYfLdRD8nUUingvu
+IbngXLs71JqQHmbXzw1WTJClXtfF6R2VZuZ6PT8ZK1bDFPvTgnkUcAk70H+VnDM5
+K48CAwEAAaOCATswggE3MB0GA1UdDgQWBBQoFRKLJrZvkNmqvw8DNuTLPyru/DCB
+zwYDVR0jBIHHMIHEgBQoFRKLJrZvkNmqvw8DNuTLPyru/KGBoKSBnTCBmjELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgTAk1BMQ8wDQYDVQQHEwZNYWxkZW4xGjAYBgNVBAoT
+EVBhaW5sZXNzIFNlY3VyaXR5MS8wLQYJKoZIhvcNAQkBFiBwb3N0bWFzdGVyQHBh
+aW5sZXNzLXNlY3VyaXR5LmNvbTEgMB4GA1UEAxMXUGFpbmxlc3MgU2VjdXJpdHks
+IEluYy6CCQDSOSuPil70MjAMBgNVHRMEBTADAQH/MDYGA1UdHwQvMC0wK6ApoCeG
+JWh0dHA6Ly93d3cuZXhhbXBsZS5jb20vZXhhbXBsZV9jYS5jcmwwDQYJKoZIhvcN
+AQEFBQADggEBAIN38UOXvwd89+a89V+/rjeN8JfpcjafLf0c2I3nex9OxBWji5bf
+cWTNfm1t9GpS4HhVT2tl5xdxyW5UrE9Q+oFadN0LxtRPbGU+Gvt4pVo8Pst6/2P8
+PA3/OA1UchIpZR6EWQQsws4esNLLwDbj48MkQdVCjpp1cVpFVmJUzYYFD9h9EMK2
+kxpGf5wfp9LI2A5/qACNQPBDfRsR+dcNBsBbmD1LulqputUPuKPXnVbHWL28VZUY
+PITHl2Ndbmk6znSu7ILef3CGyeXqTTj+Jo+5AQz3sneko6oMn8PqfRj1h0uUyykT
+lavp3iTNstQs/rdqdI+lPYMokDKXRSD3pK8=
</ca-cert>
<subject>Painless Security Server Certificate</subject>
</trust-anchor>
<service>email/painless-security.com</service>
</services>
<trust-anchor>
- <server-cert>3838E17EC9A2A06D7B6030E3C5727E3466EAB4BB4159DCE7CF6297ADAFC8A56F</server-cert>
+ <server-cert>4242424242424242424242424242424242424242424242424242424242424242</server-cert>
</trust-anchor>
</identity>