gboolean debug = 0;
+/* Usually /etc/pki/tls/certs/ca-bundle.crt unless overridden during
+ * configure or on the command line.
+ */
+const char *cainfo = CAINFO;
+gboolean check_cert = TRUE;
+
/* Private functions. */
static void start_ui (void);
static GtkWidget *menu_item_new (int which_menu);
"Use '" PACKAGE " --help' to see a list of available command line options";
static const GOptionEntry options[] = {
+ { "cainfo", 0, 0, G_OPTION_ARG_STRING, &cainfo,
+ "set the path of the CA certificate bundle", NULL },
+ { "check-certificate", 0, 0, G_OPTION_ARG_NONE, &check_cert,
+ "if --no-check-certificate is passed we don't check the SSL certificate of the server", NULL },
{ "debug", 'd', 0, G_OPTION_ARG_NONE, &debug,
"turn on debugging messages", NULL },
{ "version", 'V', 0, G_OPTION_ARG_NONE, &print_version,
#include <glib.h>
+#include <curl/curl.h>
+
#include "internal.h"
/* Private functions. */
static gpointer wui_thread (gpointer data);
static void wui_thread_send_quit (void);
+static void do_curl_init (void);
static gboolean do_connect (void);
static gboolean do_login (void);
static void refresh_vm_list (void);
/* The private state of the WUI thread. */
static int secs_between_refresh = 60;
+static CURL *curl = NULL;
+static char curl_error_buffer[CURL_ERROR_SIZE];
static char *uri = NULL;
static char *username = NULL;
static char *password = NULL;
msg = (struct message *) _msg;
if (msg) {
- DEBUG ("received message %d", msg->type);
+ DEBUG ("received message with msg->type = %d", msg->type);
quit = process_message (msg);
/* Don't free any strings in the message - we've saved them. */
g_free (msg);
{
switch (msg->type) {
case QUIT:
+ if (curl) curl_easy_cleanup (curl);
if (uri) g_free (uri);
if (username) g_free (username);
if (password) g_free (password);
return 1;
case CONNECT:
+ if (curl) curl_easy_cleanup (curl);
+ do_curl_init ();
if (uri) g_free (uri);
uri = msg->str1;
case DISCONNECT:
/* This just forgets the state. REST is connectionless. */
+ if (curl) curl_easy_cleanup (curl);
+ curl = NULL;
if (uri) g_free (uri);
+ uri = NULL;
if (username) g_free (username);
+ username = NULL;
if (password) g_free (password);
+ password = NULL;
set_connected (FALSE);
set_logged_in (FALSE);
break;
if (password) g_free (password);
password = msg->str2;
+ /* If we're not connected, this message just updates the
+ * username and password. Otherwise if we are connected,
+ * try to login and grab the initial list of VMs.
+ */
if (connected) {
if (do_login ()) {
set_logged_in (TRUE);
break;
case REFRESH_VM_LIST:
- refresh_vm_list ();
- secs_between_refresh = 60;
+ if (connected && logged_in) {
+ refresh_vm_list ();
+ secs_between_refresh = 60;
+ }
break;
default:
return 0;
}
-/* Try to connect to the current URI. Returns true on success. */
+/* Macro for easy handling of CURL errors. */
+#define CURL_CHECK_ERROR(fn, args) \
+ ({ \
+ CURLcode __r = fn args; \
+ if (__r != CURLE_OK) { \
+ fprintf (stderr, "%s: %s\n", #fn, curl_easy_strerror (__r)); \
+ } \
+ __r; \
+ })
+
+static size_t
+write_fn (void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ int bytes = size * nmemb;
+ return bytes;
+}
+
+static size_t
+header_fn (void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ int bytes = size * nmemb;
+ return bytes;
+}
+
+/* Called from the message loop to initialize the CURL handle. */
+static void
+do_curl_init (void)
+{
+ DEBUG ("initializing libcurl");
+
+ curl = curl_easy_init ();
+ if (!curl) { /* This is probably quite bad, so abort. */
+ DEBUG ("curl_easy_init failed");
+ abort ();
+ }
+
+ CURL_CHECK_ERROR (curl_easy_setopt,
+ (curl, CURLOPT_CAINFO, cainfo));
+ CURL_CHECK_ERROR (curl_easy_setopt,
+ (curl, CURLOPT_SSL_VERIFYHOST, check_cert ? 2 : 0));
+ CURL_CHECK_ERROR (curl_easy_setopt,
+ (curl, CURLOPT_SSL_VERIFYPEER, check_cert ? 1 : 0));
+
+ CURL_CHECK_ERROR (curl_easy_setopt,
+ (curl, CURLOPT_WRITEFUNCTION, write_fn));
+ CURL_CHECK_ERROR (curl_easy_setopt,
+ (curl, CURLOPT_HEADERFUNCTION, header_fn));
+
+ /* This enables error messages in curl_easy_perform. */
+ CURL_CHECK_ERROR (curl_easy_setopt,
+ (curl, CURLOPT_ERRORBUFFER, curl_error_buffer));
+
+ /* This enables cookie handling, using an internal cookiejar. */
+ CURL_CHECK_ERROR (curl_easy_setopt,
+ (curl, CURLOPT_COOKIEFILE, ""));
+}
+
+/* Called from the message loop. Try to connect to the current URI.
+ * Returns true on success.
+ */
static gboolean
do_connect (void)
{
+ long code = 0;
+
DEBUG ("connecting to uri %s", uri);
- return FALSE;
+
+ /* Set the URI for libcurl. */
+ CURL_CHECK_ERROR (curl_easy_setopt, (curl, CURLOPT_URL, uri));
+
+ /* Try to fetch the URI. */
+ if (CURL_CHECK_ERROR (curl_easy_perform, (curl)) != CURLE_OK)
+ return FALSE;
+
+ CURL_CHECK_ERROR (curl_easy_getinfo, (curl, CURLINFO_RESPONSE_CODE, &code));
+ DEBUG ("HTTP return code is %ld", code);
+ if (code != 200 || code != 302 || code != 401)
+ return FALSE;
+
+ return TRUE;
}
-/* Try to login to URI/login with the username and password given.
- * Returns true on success.
+/* Called from the message loop. Try to login to 'URI/login' with the
+ * current username and password. Returns true on success.
*/
static gboolean
do_login (void)
return FALSE;
}
-/* Refresh the list of VMs. */
+/* Called from the message loop. Refresh the list of VMs. */
static void
refresh_vm_list (void)
{