]> git.proxmox.com Git - spiceterm.git/commitdiff
use SASL for auth, always use TLS
authorDietmar Maurer <dietmar@proxmox.com>
Wed, 23 Oct 2013 08:57:11 +0000 (10:57 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Wed, 23 Oct 2013 08:58:24 +0000 (10:58 +0200)
Makefile
auth-pve.c [new file with mode: 0644]
event_loop.c
screen.c
spiceterm.h

index 9d610d052fe294bfe0abe4c545df5e9b8a6acacf..af66df6945213acb0de4a370fc5ecff0d0206c47 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 PROGRAMS=spiceterm
 
 HEADERS=translations.h event_loop.h glyphs.h spiceterm.h
-SOURCES=screen.c event_loop.c input.c spiceterm.c
+SOURCES=screen.c event_loop.c input.c spiceterm.c auth-pve.c
 
 #export G_MESSAGES_DEBUG=all 
 #export SPICE_DEBUG=1
@@ -14,7 +14,8 @@ spiceterm: ${SOURCES} ${HEADERS} spiceterm.c
 
 .PHONY: test
 test: spiceterm
-       ./spiceterm & remote-viewer spice://localhost:5912
+       #./spiceterm & remote-viewer spice://localhost:5912
+       G_MESSAGES_DEBUG=all SPICE_DEBUG=1 ./spiceterm & G_MESSAGES_DEBUG=all SPICE_DEBUG=1 remote-viewer --debug 'spice://localhost?tls-port=5912' --spice-ca-file /etc/pve/pve-root-ca.pem --spice-secure-channels=all
 
 .PHONY: distclean
 distclean: clean
diff --git a/auth-pve.c b/auth-pve.c
new file mode 100644 (file)
index 0000000..7dd5953
--- /dev/null
@@ -0,0 +1,130 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include "spiceterm.h"
+
+static char *auth_path = "/";
+static char *auth_perm = "Sys.Console";
+
+static char *
+urlencode(char *buf, const char *value)
+{
+    static const char *hexchar = "0123456789abcdef";
+    char *p = buf;
+    int i;
+    int l = strlen(value);
+    for (i = 0; i < l; i++) {
+        char c = value[i];
+        if (('a' <= c && c <= 'z') ||
+            ('A' <= c && c <= 'Z') ||
+            ('0' <= c && c <= '9')) {
+            *p++ = c;
+        } else if (c == 32) {
+            *p++ = '+';
+        } else {
+            *p++ = '%';
+            *p++ = hexchar[c >> 4];
+            *p++ = hexchar[c & 15];
+        }
+    }
+    *p = 0;
+
+    return p;
+}
+
+int 
+pve_auth_verify(const char *clientip, const char *username, const char *passwd)
+{
+    struct sockaddr_in server;
+
+    int sfd = socket(AF_INET, SOCK_STREAM, 0);
+    if (sfd == -1) {
+        perror("pve_auth_verify: socket failed");
+        return -1;
+    }
+
+    struct hostent *he;
+    if ((he = gethostbyname("localhost")) == NULL) {
+        fprintf(stderr, "pve_auth_verify: error resolving hostname\n");
+        goto err;
+    }
+
+    memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length);
+    server.sin_family = AF_INET;
+    server.sin_port = htons(85);
+
+    if (connect(sfd, (struct sockaddr *)&server, sizeof(server))) {
+        perror("pve_auth_verify: error connecting to server");
+        goto err;
+    }
+
+    char buf[8192];
+    char form[8192];
+
+    char *p = form;
+    p = urlencode(p, "username");
+    *p++ = '=';
+    p = urlencode(p, username);
+
+    *p++ = '&';
+    p = urlencode(p, "password");
+    *p++ = '=';
+    p = urlencode(p, passwd);
+
+    *p++ = '&';
+    p = urlencode(p, "path");
+    *p++ = '=';
+    p = urlencode(p, auth_path);
+
+    *p++ = '&';
+    p = urlencode(p, "privs");
+    *p++ = '=';
+    p = urlencode(p, auth_perm);
+
+    sprintf(buf, "POST /api2/json/access/ticket HTTP/1.1\n"
+            "Host: localhost:85\n"
+            "Connection: close\n"
+            "PVEClientIP: %s\n"
+            "Content-Type: application/x-www-form-urlencoded\n"
+            "Content-Length: %zd\n\n%s\n", clientip, strlen(form), form);
+    ssize_t len = strlen(buf);
+    ssize_t sb = send(sfd, buf, len, 0);
+    if (sb < 0) {
+        perror("pve_auth_verify: send failed");
+        goto err;
+    }
+    if (sb != len) {
+        fprintf(stderr, "pve_auth_verify: partial send error\n");
+        goto err;
+    }
+
+    len = recv(sfd, buf, sizeof(buf) - 1, 0);
+    if (len < 0) {
+        perror("pve_auth_verify: recv failed");
+        goto err;
+    }
+
+    buf[len] = 0;
+
+    //printf("DATA:%s\n", buf);
+
+    shutdown(sfd, SHUT_RDWR);
+
+    if (!strncmp(buf, "HTTP/1.1 200 OK", 15)) {
+        return 0;
+    }
+
+    char *firstline = strtok(buf, "\n");
+    
+    fprintf(stderr, "auth failed: %s\n", firstline);
+
+    return -1;
+
+err:
+    shutdown(sfd, SHUT_RDWR);
+    return -1;
+}
index 5235b87ce2acf75da38c3f7fe2796b1d94bd1532..1583a1884ae9e803de9174312fc38089402c6a4a 100644 (file)
@@ -27,9 +27,6 @@
 #include <sys/time.h>
 #include <signal.h>
 #include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
 
 #include <glib.h>
 
@@ -44,10 +41,6 @@ static int debug = 0;
     } \
 }
 
-static char *auth_path = "/";
-static char *auth_perm = "Sys.Console";
-static char clientip[INET6_ADDRSTRLEN];
-
 static GMainLoop *main_loop;
 
 static SpiceCoreInterface core;
@@ -229,131 +222,6 @@ static void ignore_sigpipe(void)
     sigaction(SIGPIPE, &act, NULL);
 }
 
-static char *
-urlencode(char *buf, const char *value)
-{
-    static const char *hexchar = "0123456789abcdef";
-    char *p = buf;
-    int i;
-    int l = strlen(value);
-    for (i = 0; i < l; i++) {
-        char c = value[i];
-        if (('a' <= c && c <= 'z') ||
-            ('A' <= c && c <= 'Z') ||
-            ('0' <= c && c <= '9')) {
-            *p++ = c;
-        } else if (c == 32) {
-            *p++ = '+';
-        } else {
-            *p++ = '%';
-            *p++ = hexchar[c >> 4];
-            *p++ = hexchar[c & 15];
-        }
-    }
-    *p = 0;
-
-    return p;
-}
-
-static int 
-pve_auth_verify(const char *clientip, const char *username, const char *passwd)
-{
-    struct sockaddr_in server;
-
-    int sfd = socket(AF_INET, SOCK_STREAM, 0);
-    if (sfd == -1) {
-        perror("pve_auth_verify: socket failed");
-        return -1;
-    }
-
-    struct hostent *he;
-    if ((he = gethostbyname("localhost")) == NULL) {
-        fprintf(stderr, "pve_auth_verify: error resolving hostname\n");
-        goto err;
-    }
-
-    memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length);
-    server.sin_family = AF_INET;
-    server.sin_port = htons(85);
-
-    if (connect(sfd, (struct sockaddr *)&server, sizeof(server))) {
-        perror("pve_auth_verify: error connecting to server");
-        goto err;
-    }
-
-    char buf[8192];
-    char form[8192];
-
-    char *p = form;
-    p = urlencode(p, "username");
-    *p++ = '=';
-    p = urlencode(p, username);
-
-    *p++ = '&';
-    p = urlencode(p, "password");
-    *p++ = '=';
-    p = urlencode(p, passwd);
-
-    *p++ = '&';
-    p = urlencode(p, "path");
-    *p++ = '=';
-    p = urlencode(p, auth_path);
-
-    *p++ = '&';
-    p = urlencode(p, "privs");
-    *p++ = '=';
-    p = urlencode(p, auth_perm);
-
-    sprintf(buf, "POST /api2/json/access/ticket HTTP/1.1\n"
-            "Host: localhost:85\n"
-            "Connection: close\n"
-            "PVEClientIP: %s\n"
-            "Content-Type: application/x-www-form-urlencoded\n"
-            "Content-Length: %zd\n\n%s\n", clientip, strlen(form), form);
-    ssize_t len = strlen(buf);
-    ssize_t sb = send(sfd, buf, len, 0);
-    if (sb < 0) {
-        perror("pve_auth_verify: send failed");
-        goto err;
-    }
-    if (sb != len) {
-        fprintf(stderr, "pve_auth_verify: partial send error\n");
-        goto err;
-    }
-
-    len = recv(sfd, buf, sizeof(buf) - 1, 0);
-    if (len < 0) {
-        perror("pve_auth_verify: recv failed");
-        goto err;
-    }
-
-    buf[len] = 0;
-
-    //printf("DATA:%s\n", buf);
-
-    shutdown(sfd, SHUT_RDWR);
-
-    if (!strncmp(buf, "HTTP/1.1 200 OK", 15)) {
-        return 0;
-    }
-
-    char *firstline = strtok(buf, "\n");
-    
-    fprintf(stderr, "auth failed: %s\n", firstline);
-
-    return -1;
-
-err:
-    shutdown(sfd, SHUT_RDWR);
-    return -1;
-}
-
-static int
-verify_credentials(const char *username, const char *password)
-{
-    return pve_auth_verify(clientip, username, password);
-}
-
 SpiceCoreInterface *basic_event_loop_init(void)
 {
     main_loop = g_main_loop_new(NULL, FALSE);
@@ -370,8 +238,6 @@ SpiceCoreInterface *basic_event_loop_init(void)
     core.watch_remove = watch_remove;
     core.channel_event = channel_event;
 
-    core.auth_plain_verify_credentials = verify_credentials;
-
     ignore_sigpipe();
 
     return &core;
index 53924e028d6b5b121f7cf92830f44c01a89721c0..b3b8eaf7276127af949ff170f73d4cb65b5d6960 100644 (file)
--- a/screen.c
+++ b/screen.c
@@ -40,6 +40,7 @@
 #include <spice/macros.h>
 #include <spice/qxl_dev.h>
 #include <spice/vd_agent.h>
+#include <sasl/sasl.h>
 
 #include "glyphs.h"
 
@@ -706,12 +707,64 @@ spice_screen_draw_char(SpiceScreen *spice_screen, int x, int y, gunichar2 ch,
     push_command(spice_screen, &update->ext);
 }
 
+static int 
+sasl_checkpass_cb(sasl_conn_t *conn,
+                  void *context,
+                  const char *user,
+                  const char *pass,
+                  unsigned passlen,
+                  struct propctx *propctx)
+{
+    const void *remoteport = NULL;
+    char *clientip = NULL;
+    if (sasl_getprop(conn, SASL_IPREMOTEPORT, &remoteport) == SASL_OK) {
+        clientip = strtok(g_strdup(remoteport), ";");
+    } else {
+        clientip = g_strdup("unknown");
+    }
+
+    int res = pve_auth_verify(clientip, user, pass);
+
+    g_free(clientip);
+
+    return (res == 0) ? SASL_OK : SASL_NOAUTHZ;
+}
+
+static int 
+sasl_getopt_cb(void *context, const char *plugin_name,
+               const char *option,
+               const char **result, unsigned *len)
+{
+    if (strcmp(option, "mech_list") == 0) {
+        *result = "plain";
+        len = NULL;
+        return SASL_OK;
+    }
+
+    return SASL_FAIL;
+}
+
+typedef int sasl_cb_fn(void);  
+static sasl_callback_t sasl_callbacks[] = {
+    { SASL_CB_GETOPT, (sasl_cb_fn *)sasl_getopt_cb, NULL },
+    { SASL_CB_SERVER_USERDB_CHECKPASS, (sasl_cb_fn *)sasl_checkpass_cb, NULL },
+    { SASL_CB_LIST_END, NULL, NULL },
+};
 SpiceScreen *
 spice_screen_new(SpiceCoreInterface *core, uint32_t width, uint32_t height, guint timeout)
 {
     int port = 5912;
     SpiceScreen *spice_screen = g_new0(SpiceScreen, 1);
     SpiceServer* server = spice_server_new();
+    char *x509_key_file = "/etc/pve/local/pve-ssl.key";
+    char *x509_cert_file = "/etc/pve/local/pve-ssl.pem";
+    char *x509_cacert_file = "/etc/pve/pve-root-ca.pem";
+    char *x509_key_password = NULL;
+    char *x509_dh_file = NULL;
+    char *tls_ciphers = "DES-CBC3-SHA";    
+
+    gboolean use_auth = TRUE;
 
     spice_screen->width = width;
     spice_screen->height = height;
@@ -728,10 +781,25 @@ spice_screen_new(SpiceCoreInterface *core, uint32_t width, uint32_t height, guin
     spice_screen->core = core;
     spice_screen->server = server;
 
-    printf("listening on port %d (unsecure)\n", port);
-
-    spice_server_set_port(server, port);
-    spice_server_set_noauth(server);
+    printf("listening on port %d (secure)\n", port);
+    // spice_server_set_addr();
+    // spice_server_set_port(spice_server, port);
+    //spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESS_OFF);
+
+    spice_server_set_tls(server, port,
+                         x509_cacert_file,
+                         x509_cert_file,
+                         x509_key_file,
+                         x509_key_password,
+                         x509_dh_file,
+                         tls_ciphers);
+
+    if (use_auth) {
+        spice_server_set_sasl(server, 1);
+        spice_server_set_sasl_callbacks(server, sasl_callbacks);
+    } else {
+        spice_server_set_noauth(server);
+    }
 
     int res = spice_server_init(server, core);
     if (res != 0) {
index cfa9428d587a563249556a7909ce335fd5c3ad9e..95c9b55e662cc0210c9adfcf440aacd446de5c1c 100644 (file)
@@ -159,4 +159,6 @@ gboolean vdagent_owns_clipboard(spiceTerm *vt);
 void vdagent_request_clipboard(spiceTerm *vt);
 void vdagent_grab_clipboard(spiceTerm *vt);
 
+int pve_auth_verify(const char *clientip, const char *username, const char *passwd);
+