Index: new/server/reds.c
===================================================================
--- new.orig/server/reds.c	2013-10-17 10:32:37.000000000 +0200
+++ new/server/reds.c	2013-10-17 13:33:53.000000000 +0200
@@ -146,6 +146,9 @@
     SpiceLinkMess *link_mess;
     int mess_pos;
     TicketInfo tiTicketing;
+    uint32_t auth_plain_header;
+    char username[1024];
+    char password[1024];
     SpiceLinkAuthMechanism auth_mechanism;
     int skip_auth;
 } RedLinkInfo;
@@ -1434,6 +1437,8 @@
 {
     if (sasl_enabled && !link->skip_auth) {
         red_channel_set_common_cap(channel, SPICE_COMMON_CAP_AUTH_SASL);
+    } else if (core && core->auth_plain_verify_credentials) {
+        red_channel_set_common_cap(channel, SPICE_COMMON_CAP_AUTH_PLAIN);
     } else {
         red_channel_set_common_cap(channel, SPICE_COMMON_CAP_AUTH_SPICE);
     }
@@ -2125,6 +2130,64 @@
     async_read_handler(0, 0, &link->asyc_read);
 }
 
+static void reds_handle_auth_plain_password(void *opaque)
+{
+    RedLinkInfo *link = (RedLinkInfo *)opaque;
+
+    uint16_t password_len = link->auth_plain_header >> 16;
+    link->password[password_len] = 0;
+
+    if (core && core->auth_plain_verify_credentials && !link->skip_auth) {
+        int res;
+        if ((res = core->auth_plain_verify_credentials(link->username, link->password)) != 0) {
+            spice_warning("auth_plain failed - error %d", res);
+            reds_send_link_result(link, SPICE_LINK_ERR_PERMISSION_DENIED);
+            reds_link_free(link);
+            return;
+        }
+    }
+
+    reds_handle_link(link);
+}
+
+static void reds_handle_auth_plain_username(void *opaque)
+{
+    RedLinkInfo *link = (RedLinkInfo *)opaque;
+    AsyncRead *obj = &link->asyc_read;
+
+    uint16_t username_len = link->auth_plain_header & 0xffff;
+    uint16_t password_len = link->auth_plain_header >> 16;
+    link->username[username_len] = 0;
+
+    obj->now = (uint8_t *)link->password;
+    obj->end = obj->now + password_len;
+    obj->done = reds_handle_auth_plain_password;
+    async_read_handler(0, 0, &link->asyc_read);
+}
+
+static void reds_handle_auth_plain_header(void *opaque)
+{
+    RedLinkInfo *link = (RedLinkInfo *)opaque;
+    AsyncRead *obj = &link->asyc_read;
+
+    uint16_t username_len = link->auth_plain_header & 0xffff;
+
+    obj->now = (uint8_t *)link->username;
+    obj->end = obj->now + username_len;
+    obj->done = reds_handle_auth_plain_username;
+    async_read_handler(0, 0, &link->asyc_read);
+}
+
+static void reds_start_auth_plain(RedLinkInfo *link)
+{
+    AsyncRead *obj = &link->asyc_read;
+
+    obj->now = (uint8_t *)&link->auth_plain_header;
+    obj->end = obj->now + sizeof(link->auth_plain_header);
+    obj->done = reds_handle_auth_plain_header;
+    async_read_handler(0, 0, &link->asyc_read);
+}
+
 #if HAVE_SASL
 static char *addr_to_string(const char *format,
                             struct sockaddr_storage *sa,
@@ -2651,6 +2714,8 @@
         spice_info("Starting SASL");
         reds_start_auth_sasl(link);
 #endif
+    } else if (link->auth_mechanism.auth_mechanism == SPICE_COMMON_CAP_AUTH_PLAIN) {
+        reds_start_auth_plain(link);
     } else {
         spice_warning("Unknown auth method, disconnecting");
         if (sasl_enabled) {
Index: new/server/spice.h
===================================================================
--- new.orig/server/spice.h	2013-10-17 10:32:40.000000000 +0200
+++ new/server/spice.h	2013-10-17 12:44:58.000000000 +0200
@@ -44,7 +44,7 @@
 
 #define SPICE_INTERFACE_CORE "core"
 #define SPICE_INTERFACE_CORE_MAJOR 1
-#define SPICE_INTERFACE_CORE_MINOR 3
+#define SPICE_INTERFACE_CORE_MINOR 4
 typedef struct SpiceCoreInterface SpiceCoreInterface;
 
 #define SPICE_WATCH_EVENT_READ  (1 << 0)
@@ -91,6 +91,7 @@
     void (*watch_remove)(SpiceWatch *watch);
 
     void (*channel_event)(int event, SpiceChannelEventInfo *info);
+    int (*auth_plain_verify_credentials)(const char *username, const char *password);
 };
 
 /* qxl interface */

