Implement SSL certificate verification option (default, and per-feed).
authorColin Leroy <colin@colino.net>
Tue, 29 Apr 2014 08:33:38 +0000 (10:33 +0200)
committerColin Leroy <colin@colino.net>
Tue, 29 Apr 2014 08:34:36 +0000 (10:34 +0200)
Fixes bug #3106, "Rssyl plugin does not verify SSL peer at all"

src/plugins/rssyl/feed.c
src/plugins/rssyl/feed.h
src/plugins/rssyl/feedprops.c
src/plugins/rssyl/feedprops.h
src/plugins/rssyl/rssyl.c
src/plugins/rssyl/rssyl.h
src/plugins/rssyl/rssyl_gtk.c
src/plugins/rssyl/rssyl_gtk.h
src/plugins/rssyl/rssyl_prefs.c
src/plugins/rssyl/rssyl_prefs.h

index 35823b6..8542bc7 100644 (file)
@@ -84,6 +84,7 @@ struct _RSSylThreadCtx {
        gboolean defer_modified_check;
        gboolean ready;
        gchar *error;
+       gboolean ssl_verify_peer;
 };
 
 typedef struct _RSSylThreadCtx RSSylThreadCtx;
@@ -157,8 +158,10 @@ static void *rssyl_fetch_feed_threaded(void *arg)
        curl_easy_setopt(eh, CURLOPT_NOSIGNAL, 1);
        curl_easy_setopt(eh, CURLOPT_ENCODING, "");
 #if LIBCURL_VERSION_NUM >= 0x070a00
-       curl_easy_setopt(eh, CURLOPT_SSL_VERIFYPEER, 0);
-       curl_easy_setopt(eh, CURLOPT_SSL_VERIFYHOST, 0);
+       if(ctx->ssl_verify_peer == FALSE) {
+               curl_easy_setopt(eh, CURLOPT_SSL_VERIFYPEER, 0);
+               curl_easy_setopt(eh, CURLOPT_SSL_VERIFYHOST, 0);
+       }
 #endif
        curl_easy_setopt(eh, CURLOPT_USERAGENT,
                "Claws Mail RSSyl plugin "VERSION
@@ -287,7 +290,7 @@ gchar *rssyl_feed_title_to_dir(const gchar *title)
  * it for title, create a directory based on the title. It returns a xmlDocPtr
  * for libxml2 to parse further.
  */
-xmlDocPtr rssyl_fetch_feed(const gchar *url, time_t last_update, gchar **title, gchar **error) {
+xmlDocPtr rssyl_fetch_feed(const gchar *url, time_t last_update, gboolean ssl_verify_peer, gchar **title, gchar **error) {
        gchar *xpath, *rootnode, *dir;
        xmlDocPtr doc;
        xmlNodePtr node, n, rnode;
@@ -314,6 +317,7 @@ xmlDocPtr rssyl_fetch_feed(const gchar *url, time_t last_update, gchar **title,
        ctx->last_update = last_update;
        ctx->not_modified = FALSE;
        ctx->defer_modified_check = FALSE;
+       ctx->ssl_verify_peer = ssl_verify_peer;
 
        *title = NULL;
 
@@ -1504,7 +1508,8 @@ void rssyl_update_comments(RSSylFolderItem *ritem)
                                    (ritem->fetch_comments_for == -1 ||
                                     time(NULL) - fitem->date <= ritem->fetch_comments_for*86400)) {
                                        debug_print("RSSyl: fetching comments '%s'\n", fitem->comments_link);
-                                       doc = rssyl_fetch_feed(fitem->comments_link, ritem->item.mtime, &title, NULL);
+                                       doc = rssyl_fetch_feed(fitem->comments_link, ritem->item.mtime, 
+                                                       ritem->ssl_verify_peer, &title, NULL);
                                        rssyl_parse_feed(doc, ritem, fitem->id);
                                        xmlFreeDoc(doc);
                                        g_free(title);
@@ -1532,7 +1537,7 @@ void rssyl_update_feed(RSSylFolderItem *ritem)
 
        log_print(LOG_PROTOCOL, RSSYL_LOG_UPDATING, ritem->url);
 
-       doc = rssyl_fetch_feed(ritem->url, ritem->item.mtime, &title, &error);
+       doc = rssyl_fetch_feed(ritem->url, ritem->item.mtime, ritem->ssl_verify_peer, &title, &error);
 
        if (claws_is_exiting()) {
                debug_print("RSSyl: Claws-Mail is exiting, aborting feed parsing\n");
@@ -1725,7 +1730,7 @@ FolderItem *rssyl_subscribe_new_feed(FolderItem *parent, const gchar *url,
        }
        
        main_window_cursor_wait(mainwindow_get_mainwindow());
-       doc = rssyl_fetch_feed(myurl, -1, &title, &error);
+       doc = rssyl_fetch_feed(myurl, -1, rssyl_prefs_get()->ssl_verify_peer, &title, &error);
        main_window_cursor_normal(mainwindow_get_mainwindow());
        if( !doc || !title ) {
                if (verbose) {
index 21b0745..1d66b7d 100644 (file)
@@ -71,7 +71,7 @@ struct _RSSylParseCtx {
 
 typedef struct _RSSylParseCtx RSSylParseCtx;
 
-xmlDocPtr rssyl_fetch_feed(const gchar *url, time_t last_update, gchar **title, gchar **error);
+xmlDocPtr rssyl_fetch_feed(const gchar *url, time_t last_update, gboolean ssl_verify_peer, gchar **title, gchar **error);
 void rssyl_parse_feed(xmlDocPtr doc, RSSylFolderItem *ritem, gchar *parent);
 gboolean rssyl_add_feed_item(RSSylFolderItem *ritem, RSSylFeedItem *fitem);
 MsgInfo *rssyl_parse_feed_item_to_msginfo(gchar *file, MsgFlags flags,
index 3b8f651..d52bde5 100644 (file)
@@ -125,6 +125,10 @@ void rssyl_store_feed_props(RSSylFolderItem *ritem)
                                xmlSetProp(node, RSSYL_PROP_SILENT_UPDATE, t_prop);
                                g_free(t_prop);
 
+                               t_prop = g_strdup_printf("%d", ritem->ssl_verify_peer);
+                               xmlSetProp(node, RSSYL_PROP_SSL_VERIFY_PEER, t_prop);
+                               g_free(t_prop);
+
                                found = TRUE;
                        }
                        xmlFree(tmp);
@@ -278,6 +282,16 @@ void rssyl_get_feed_props(RSSylFolderItem *ritem)
                                xmlFree(tmp);
                                tmp = NULL;
 
+                               /* ssl_verify_peer */
+                               tmp = xmlGetProp(node, RSSYL_PROP_SSL_VERIFY_PEER);
+                               tmpi = 0;
+                               if( tmp ) {
+                                       tmpi = atoi(tmp);
+                                       ritem->ssl_verify_peer = tmpi;
+                               }
+                               xmlFree(tmp);
+                               tmp = NULL;
+
                                tmp = xmlGetProp(node, RSSYL_PROP_EXPIRED);
 
                                if( ritem->default_expired_num )
index f8ff498..f4a3b27 100644 (file)
@@ -16,6 +16,7 @@
 #define RSSYL_PROP_FETCH_COMMENTS              "fetch_comments"
 #define RSSYL_PROP_FETCH_COMMENTS_FOR          "fetch_comments_for"
 #define RSSYL_PROP_SILENT_UPDATE "silent_update"
+#define RSSYL_PROP_SSL_VERIFY_PEER "ssl_verify_peer"
 
 void rssyl_store_feed_props(RSSylFolderItem *ritem);
 void rssyl_get_feed_props(RSSylFolderItem *ritem);
index 282ffe4..670dd86 100644 (file)
@@ -296,6 +296,7 @@ static FolderItem *rssyl_item_new(Folder *folder)
        ritem->refresh_id = 0;
        ritem->expired_num = rssyl_prefs_get()->expired;
        ritem->last_count = 0;
+       ritem->ssl_verify_peer = rssyl_prefs_get()->ssl_verify_peer;
 
        ritem->contents = NULL;
        ritem->feedprop = NULL;
index 541a898..917adbe 100644 (file)
@@ -34,6 +34,7 @@ struct _RSSylFolderItem {
        gboolean fetch_comments;
        gint fetch_comments_for;
        gint silent_update;
+       gboolean ssl_verify_peer;
 
        struct _RSSylFeedProp *feedprop;
 };
index 86d1670..3a581dc 100644 (file)
@@ -234,7 +234,7 @@ static RSSylFeedProp *rssyl_gtk_prop_real(RSSylFolderItem *ritem)
                                                *expired_label, *hsep, *sep, *bbox, *cancel_button, *cancel_align,
                                                *cancel_hbox, *cancel_image, *cancel_label, *ok_button, *ok_align,
                                                *ok_hbox, *ok_image, *ok_label, *silent_update_label;
-       GtkWidget *ssl_verify_peer_checkbtn;
+
        GtkObject *refresh_adj, *expired_adj, *fetch_comments_for_adj;
        gint refresh, expired;
        gint row = 0;
@@ -452,6 +452,24 @@ static RSSylFeedProp *rssyl_gtk_prop_real(RSSylFolderItem *ritem)
        gtk_combo_box_set_active(GTK_COMBO_BOX(feedprop->silent_update),
                        ritem->silent_update);
 
+       row++;
+       hsep = gtk_hseparator_new();
+       gtk_widget_set_size_request(hsep, -1, 10);
+       gtk_table_attach(GTK_TABLE(table), hsep, 0, 2, row, row+1,
+                       (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                       (GtkAttachOptions) (0), 10, 5);
+
+       row++;
+       feedprop->ssl_verify_peer_checkbtn = gtk_check_button_new_with_label(
+               _("Verify SSL certificate validity"));
+       gtk_widget_show(feedprop->ssl_verify_peer_checkbtn);
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(feedprop->ssl_verify_peer_checkbtn), 
+                       ritem->ssl_verify_peer);
+       gtk_table_attach(GTK_TABLE(table), feedprop->ssl_verify_peer_checkbtn, 0, 1, row, row+1,
+                       (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                       (GtkAttachOptions) (0), 10, 5);
+
+
        /* Separator above the button box */
        sep = gtk_hseparator_new();
        gtk_widget_set_size_request(sep, -1, 10);
@@ -610,6 +628,9 @@ void rssyl_gtk_prop_store(RSSylFolderItem *ritem)
        if( ritem->silent_update < 0 )
                ritem->silent_update = 0;
 
+       ritem->ssl_verify_peer = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
+                                        (ritem->feedprop->ssl_verify_peer_checkbtn));;
+
        rssyl_store_feed_props(ritem);
 
        debug_print("last_count %d, x %d, old_ex %d\n", ritem->last_count, x, old_ex);
index fdf27b3..a670a6b 100644 (file)
@@ -17,6 +17,7 @@ struct _RSSylFeedProp {
        GtkWidget *fetch_comments;
        GtkWidget *fetch_comments_for;
        GtkWidget *silent_update;
+       GtkWidget *ssl_verify_peer_checkbtn;
 };
 
 typedef struct _RSSylFeedProp RSSylFeedProp;
index ea8e73f..ab37b89 100644 (file)
@@ -48,10 +48,12 @@ static PrefParam param[] = {
                NULL, NULL, NULL },
        { "expired_keep", RSSYL_PREF_DEFAULT_EXPIRED, &rssyl_prefs.expired, P_INT,
                NULL, NULL, NULL },
-       { "refresh_on_startup", FALSE, &rssyl_prefs.refresh_on_startup, P_BOOL,
+       { "refresh_on_startup", "FALSE", &rssyl_prefs.refresh_on_startup, P_BOOL,
                NULL, NULL, NULL },
        { "cookies_path", "", &rssyl_prefs.cookies_path, P_STRING,
                NULL, NULL, NULL },
+       { "ssl_verify_peer", "TRUE", &rssyl_prefs.ssl_verify_peer, P_BOOL,
+               NULL, NULL, NULL },
        { 0, 0, 0, 0, 0, 0, 0 }
 };
 
@@ -92,11 +94,12 @@ static void create_rssyl_prefs_page(PrefsPage *page,
        GtkWidget *expired;
        GtkWidget *refresh_on_startup;
        GtkWidget *cookies_path;
+       GtkWidget *ssl_verify_peer_checkbtn;
        GtkWidget *label;
        GtkObject *refresh_adj, *expired_adj;
 
        table = gtk_table_new(RSSYL_NUM_PREFS, 2, FALSE);
-       gtk_container_set_border_width(GTK_CONTAINER(table), 5);
+       gtk_container_set_border_width(GTK_CONTAINER(table), 6);
        gtk_table_set_row_spacings(GTK_TABLE(table), VSPACING_NARROW);
        gtk_table_set_col_spacings(GTK_TABLE(table), 8);
 
@@ -145,6 +148,13 @@ static void create_rssyl_prefs_page(PrefsPage *page,
        CLAWS_SET_TIP(cookies_path,
                        _("Path to Netscape-style cookies.txt file containing your cookies"));
 
+       ssl_verify_peer_checkbtn = gtk_check_button_new_with_label(
+                       _("Verify SSL certificates validity for new feeds"));
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ssl_verify_peer_checkbtn),
+                       rssyl_prefs.ssl_verify_peer);
+       gtk_table_attach(GTK_TABLE(table), ssl_verify_peer_checkbtn, 0, 2, 5, 6,
+                       GTK_FILL | GTK_EXPAND, 0, 0, 0);
+
        gtk_widget_show_all(table);
 
        prefs_page->page.widget = table;
@@ -152,6 +162,7 @@ static void create_rssyl_prefs_page(PrefsPage *page,
        prefs_page->expired = expired;
        prefs_page->refresh_on_startup = refresh_on_startup;
        prefs_page->cookies_path = cookies_path;
+       prefs_page->ssl_verify_peer_checkbtn = ssl_verify_peer_checkbtn;
 }
 
 static void destroy_rssyl_prefs_page(PrefsPage *page)
@@ -175,6 +186,8 @@ static void save_rssyl_prefs(PrefsPage *page)
        g_free(rssyl_prefs.cookies_path);
        rssyl_prefs.cookies_path = g_strdup(gtk_entry_get_text(
                        GTK_ENTRY(prefs_page->cookies_path)));
+       rssyl_prefs.ssl_verify_peer = gtk_toggle_button_get_active(
+                       GTK_TOGGLE_BUTTON(prefs_page->ssl_verify_peer_checkbtn));
 
        pref_file = prefs_write_open(rc_file_path);
        g_free(rc_file_path);
index ba30777..15248ce 100644 (file)
@@ -15,6 +15,7 @@ struct _RSSylPrefs {
        gint expired;
        gboolean refresh_on_startup;
        gchar *cookies_path;
+       gboolean ssl_verify_peer;
 };
 
 typedef struct _RSSylPrefsPage RSSylPrefsPage;
@@ -25,6 +26,7 @@ struct _RSSylPrefsPage {
        GtkWidget *expired;
        GtkWidget *refresh_on_startup;
        GtkWidget *cookies_path;
+       GtkWidget *ssl_verify_peer_checkbtn;
 };
 
 void rssyl_prefs_init(void);