On Tue, Feb 22, 2011 at 05:09:07PM +0100, Marc-André Lureau wrote: > We introduce 2 public functions to integrate with the library user. > > spice_server_set_sasl() - turn on SASL > spice_server_set_sasl_appname() - specify the name of the app (It is > used for where to find the default configuration file) >
Do you think this could be made a separate file? reds_sasl.c? Just a thought. > The patch for QEMU is on its way. > --- > server/reds.c | 702 > +++++++++++++++++++++++++++++++++++++++++++++++++++++++- > server/reds.h | 39 +++ > server/spice.h | 2 + > 3 files changed, 737 insertions(+), 6 deletions(-) > > diff --git a/server/reds.c b/server/reds.c > index 0a26e79..1348ff7 100644 > --- a/server/reds.c > +++ b/server/reds.c > @@ -16,6 +16,8 @@ > License along with this library; if not, see > <http://www.gnu.org/licenses/>. > */ > > +#include "config.h" > + > #include <stdint.h> > #include <stdio.h> > #include <unistd.h> > @@ -38,6 +40,9 @@ > #include <openssl/rsa.h> > #include <openssl/ssl.h> > #include <openssl/err.h> > +#if HAVE_SASL > +#include <sasl/sasl.h> > +#endif > > #include "spice.h" > #include "spice-experimental.h" > @@ -53,7 +58,6 @@ > #include <spice/stats.h> > #include "stat.h" > #include "ring.h" > -#include "config.h" > #include "demarshallers.h" > #include "marshaller.h" > #include "generated_marshallers.h" > @@ -83,6 +87,10 @@ static int spice_secure_port = -1; > static char spice_addr[256]; > static int spice_family = PF_UNSPEC; > static char *default_renderer = "sw"; > +static int sasl_enabled = 0; // sasl disabled by default > +#if HAVE_SASL > +static char *sasl_appname = NULL; // default to "spice" if NULL > +#endif > > static int ticketing_enabled = 1; //Ticketing is enabled by default > static pthread_mutex_t *lock_cs; > @@ -1366,7 +1374,10 @@ static void reds_channel_set_common_caps(Channel > *channel, int cap, int active) > > void reds_channel_init_auth_caps(Channel *channel) > { > - reds_channel_set_common_caps(channel, SPICE_COMMON_CAP_AUTH_SPICE, TRUE); > + if (sasl_enabled) > + reds_channel_set_common_caps(channel, SPICE_COMMON_CAP_AUTH_SASL, > TRUE); > + else > + reds_channel_set_common_caps(channel, SPICE_COMMON_CAP_AUTH_SPICE, > TRUE); Just to be sure I understand: we either support SASL authentication, or SPICE, but never both? unless we talk to a client that doesn't understand the AUTH_SELECTION, and then we fall back to SPICE? > reds_channel_set_common_caps(channel, > SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION, TRUE); > } > > @@ -1487,7 +1498,7 @@ static void reds_handle_main_link(RedLinkInfo *link) > link_mess = link->link_mess; > reds_disconnect(); > > - if (!link_mess->connection_id) { > + if (link_mess->connection_id == 0) { > reds_send_link_result(link, SPICE_LINK_ERR_OK); > while((connection_id = rand()) == 0); > reds->agent_state.num_tokens = 0; > @@ -1671,6 +1682,100 @@ static inline void > async_read_clear_handlers(AsyncRead *obj) > obj->stream->watch = NULL; > } > > +#if HAVE_SASL > +static int sync_write_u8(RedsStream *s, uint8_t n) > +{ > + return sync_write(s, &n, sizeof(uint8_t)); > +} > + > +static int sync_write_u32(RedsStream *s, uint32_t n) > +{ > + return sync_write(s, &n, sizeof(uint32_t)); > +} > + > +ssize_t reds_stream_sasl_write(RedsStream *s, const void *buf, size_t nbyte) > +{ > + ssize_t ret; > + > + if (!s->sasl.encoded) { > + int err; > + err = sasl_encode(s->sasl.conn, (char *)buf, nbyte, > + (const char **)&s->sasl.encoded, > + &s->sasl.encodedLength); > + if (err != SASL_OK) { > + red_printf("sasl_encode error: %d", err); > + return -1; > + } > + > + if (s->sasl.encodedLength == 0) > + return 0; Missing {} > + if (!s->sasl.encoded) { > + red_printf("sasl_encode didn't return a buffer!"); > + return 0; > + } > + > + s->sasl.encodedOffset = 0; > + } > + > + ret = s->write(s, s->sasl.encoded + s->sasl.encodedOffset, > + s->sasl.encodedLength - s->sasl.encodedOffset); > + > + if (ret <= 0) > + return ret; Also missing {} > + > + s->sasl.encodedOffset += ret; > + if (s->sasl.encodedOffset == s->sasl.encodedLength) { > + s->sasl.encoded = NULL; > + s->sasl.encodedOffset = s->sasl.encodedLength = 0; > + return nbyte; > + } > + > + /* we didn't flush the encoded buffer */ > + errno = EAGAIN; > + return -1; > +} > + > +static ssize_t reds_stream_sasl_read(RedsStream *s, void *buf, size_t nbyte) > +{ > + uint8_t encoded[4096]; > + const char *decoded; > + unsigned int decodedlen; > + int err; > + int n; > + > + n = spice_buffer_copy(&s->sasl.inbuffer, buf, nbyte); > + if (n > 0) { > + spice_buffer_remove(&s->sasl.inbuffer, n); > + if (n == nbyte) > + return n; > + nbyte -= n; > + buf += n; > + } > + > + n = s->read(s, encoded, sizeof(encoded)); > + if (n <= 0) > + return n; 3rd time. > + > + err = sasl_decode(s->sasl.conn, > + (char *)encoded, n, > + &decoded, &decodedlen); > + if (err != SASL_OK) { > + red_printf("sasl_decode error: %d", err); > + return -1; > + } > + > + if (decodedlen == 0) { > + errno = EAGAIN; > + return -1; > + } > + > + n = MIN(nbyte, decodedlen); > + memcpy(buf, decoded, n); > + spice_buffer_append(&s->sasl.inbuffer, decoded + n, decodedlen - n); > + return n; > +} > +#endif > + > static void async_read_handler(int fd, int event, void *data) > { > AsyncRead *obj = (AsyncRead *)data; > @@ -1723,16 +1828,531 @@ static void reds_get_spice_ticket(RedLinkInfo *link) > async_read_handler(0, 0, &link->asyc_read); > } > > +#if HAVE_SASL > +static char *addr_to_string(const char *format, > + struct sockaddr *sa, > + socklen_t salen) { > + char *addr; > + char host[NI_MAXHOST]; > + char serv[NI_MAXSERV]; > + int err; > + size_t addrlen; > + > + if ((err = getnameinfo(sa, salen, > + host, sizeof(host), > + serv, sizeof(serv), > + NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { > + red_printf("Cannot resolve address %d: %s", > + err, gai_strerror(err)); > + return NULL; > + } > + > + /* Enough for the existing format + the 2 vars we're > + * substituting in. */ > + addrlen = strlen(format) + strlen(host) + strlen(serv); > + addr = spice_malloc(addrlen + 1); > + snprintf(addr, addrlen, format, host, serv); > + addr[addrlen] = '\0'; > + > + return addr; > +} > + > +static int auth_sasl_check_ssf(RedsSASLContext *sasl, int *runSSF) > +{ > + const void *val; > + int err, ssf; > + > + *runSSF = 0; > + if (!sasl->wantSSF) > + return 1; > + > + err = sasl_getprop(sasl->conn, SASL_SSF, &val); > + if (err != SASL_OK) > + return 0; > + > + ssf = *(const int *)val; > + red_printf("negotiated an SSF of %d", ssf); > + if (ssf < 56) > + return 0; /* 56 is good for Kerberos */ > + > + *runSSF = 1; > + > + /* We have a SSF that's good enough */ > + return 1; > +} > + > +/* > + * Step Msg > + * > + * Input from client: > + * > + * u32 clientin-length > + * u8-array clientin-string > + * > + * Output to client: > + * > + * u32 serverout-length > + * u8-array serverout-strin > + * u8 continue > + */ > +#define SASL_DATA_MAX_LEN (1024 * 1024) > + > +static void reds_handle_auth_sasl_steplen(void *opaque); > + > +static void reds_handle_auth_sasl_step(void *opaque) > +{ > + const char *serverout; > + unsigned int serveroutlen; > + int err; > + char *clientdata = NULL; > + RedLinkInfo *link = (RedLinkInfo *)opaque; > + RedsSASLContext *sasl = &link->stream->sasl; > + uint32_t datalen = sasl->len; > + AsyncRead *obj = &link->asyc_read; > + > + /* NB, distinction of NULL vs "" is *critical* in SASL */ > + if (datalen) { > + clientdata = sasl->data; > + clientdata[datalen - 1] = '\0'; /* Wire includes '\0', but make sure > */ > + datalen--; /* Don't count NULL byte when passing to _start() */ > + } > + > + red_printf("Step using SASL Data %p (%d bytes)", > + clientdata, datalen); > + err = sasl_server_step(sasl->conn, > + clientdata, > + datalen, > + &serverout, > + &serveroutlen); > + if (err != SASL_OK && > + err != SASL_CONTINUE) { > + red_printf("sasl step failed %d (%s)", > + err, sasl_errdetail(sasl->conn)); > + goto authabort; > + } > + > + if (serveroutlen > SASL_DATA_MAX_LEN) { > + red_printf("sasl step reply data too long %d", > + serveroutlen); > + goto authabort; > + } > + > + red_printf("SASL return data %d bytes, %p", serveroutlen, serverout); > + > + if (serveroutlen) { > + serveroutlen += 1; > + sync_write(link->stream, &serveroutlen, sizeof(uint32_t)); > + sync_write(link->stream, serverout, serveroutlen); > + } else { > + sync_write(link->stream, &serveroutlen, sizeof(uint32_t)); > + } > + > + /* Whether auth is complete */ > + sync_write_u8(link->stream, err == SASL_CONTINUE ? 0 : 1); > + > + if (err == SASL_CONTINUE) { > + red_printf("%s", "Authentication must continue (step)"); > + /* Wait for step length */ > + obj->now = (uint8_t *)&sasl->len; > + obj->end = obj->now + sizeof(uint32_t); > + obj->done = reds_handle_auth_sasl_steplen; > + async_read_handler(0, 0, &link->asyc_read); > + } else { > + int ssf; > + > + if (auth_sasl_check_ssf(sasl, &ssf) == 0) { > + red_printf("Authentication rejected for weak SSF"); > + goto authreject; > + } > + > + red_printf("Authentication successful"); > + sync_write_u32(link->stream, SPICE_LINK_ERR_OK); /* Accept auth */ > + > + /* > + * Delay writing in SSF encoded until now > + */ > + sasl->runSSF = ssf; > + link->stream->writev = NULL; /* make sure writev isn't called > directly anymore */ > + > + reds_handle_link(link); > + } > + > + return; > + > +authreject: > + sync_write_u32(link->stream, 1); /* Reject auth */ > + sync_write_u32(link->stream, sizeof("Authentication failed")); > + sync_write(link->stream, "Authentication failed", sizeof("Authentication > failed")); > + > +authabort: > + reds_link_free(link); > + return; > +} > + > +static void reds_handle_auth_sasl_steplen(void *opaque) > +{ > + RedLinkInfo *link = (RedLinkInfo *)opaque; > + AsyncRead *obj = &link->asyc_read; > + RedsSASLContext *sasl = &link->stream->sasl; > + > + red_printf("Got steplen %d", sasl->len); > + if (sasl->len > SASL_DATA_MAX_LEN) { > + red_printf("Too much SASL data %d", sasl->len); > + reds_link_free(link); > + return; > + } > + > + if (sasl->len == 0) > + return reds_handle_auth_sasl_step(opaque); > + else { > + sasl->data = spice_realloc(sasl->data, sasl->len); > + obj->now = (uint8_t *)sasl->data; > + obj->end = obj->now + sasl->len; > + obj->done = reds_handle_auth_sasl_step; > + async_read_handler(0, 0, &link->asyc_read); > + } > +} > + > +/* > + * Start Msg > + * > + * Input from client: > + * > + * u32 clientin-length > + * u8-array clientin-string > + * > + * Output to client: > + * > + * u32 serverout-length > + * u8-array serverout-strin > + * u8 continue > + */ > + > + > +static void reds_handle_auth_sasl_start(void *opaque) > +{ > + RedLinkInfo *link = (RedLinkInfo *)opaque; > + AsyncRead *obj = &link->asyc_read; > + const char *serverout; > + unsigned int serveroutlen; > + int err; > + char *clientdata = NULL; > + RedsSASLContext *sasl = &link->stream->sasl; > + uint32_t datalen = sasl->len; > + > + /* NB, distinction of NULL vs "" is *critical* in SASL */ > + if (datalen) { > + clientdata = sasl->data; > + clientdata[datalen - 1] = '\0'; /* Should be on wire, but make sure > */ > + datalen--; /* Don't count NULL byte when passing to _start() */ > + } > + > + red_printf("Start SASL auth with mechanism %s. Data %p (%d bytes)", > + sasl->mechlist, clientdata, datalen); > + err = sasl_server_start(sasl->conn, > + sasl->mechlist, > + clientdata, > + datalen, > + &serverout, > + &serveroutlen); > + if (err != SASL_OK && > + err != SASL_CONTINUE) { > + red_printf("sasl start failed %d (%s)", > + err, sasl_errdetail(sasl->conn)); > + goto authabort; > + } > + > + if (serveroutlen > SASL_DATA_MAX_LEN) { > + red_printf("sasl start reply data too long %d", > + serveroutlen); > + goto authabort; > + } > + > + red_printf("SASL return data %d bytes, %p", serveroutlen, serverout); > + > + if (serveroutlen) { > + serveroutlen += 1; > + sync_write(link->stream, &serveroutlen, sizeof(uint32_t)); > + sync_write(link->stream, serverout, serveroutlen); > + } else { > + sync_write(link->stream, &serveroutlen, sizeof(uint32_t)); > + } > + > + /* Whether auth is complete */ > + sync_write_u8(link->stream, err == SASL_CONTINUE ? 0 : 1); > + > + if (err == SASL_CONTINUE) { > + red_printf("%s", "Authentication must continue (start)"); > + /* Wait for step length */ > + obj->now = (uint8_t *)&sasl->len; > + obj->end = obj->now + sizeof(uint32_t); > + obj->done = reds_handle_auth_sasl_steplen; > + async_read_handler(0, 0, &link->asyc_read); > + } else { > + int ssf; > + > + if (auth_sasl_check_ssf(sasl, &ssf) == 0) { > + red_printf("Authentication rejected for weak SSF"); > + goto authreject; > + } > + > + red_printf("Authentication successful"); > + sync_write_u32(link->stream, SPICE_LINK_ERR_OK); /* Accept auth */ > + > + /* > + * Delay writing in SSF encoded until now > + */ > + sasl->runSSF = ssf; > + link->stream->writev = NULL; /* make sure writev isn't called > directly anymore */ > + > + reds_handle_link(link); > + } > + > + return; > + > +authreject: > + sync_write_u32(link->stream, 1); /* Reject auth */ > + sync_write_u32(link->stream, sizeof("Authentication failed")); > + sync_write(link->stream, "Authentication failed", sizeof("Authentication > failed")); > + > +authabort: > + reds_link_free(link); > + return; > +} > + > +static void reds_handle_auth_startlen(void *opaque) > +{ > + RedLinkInfo *link = (RedLinkInfo *)opaque; > + AsyncRead *obj = &link->asyc_read; > + RedsSASLContext *sasl = &link->stream->sasl; > + > + red_printf("Got client start len %d", sasl->len); > + if (sasl->len > SASL_DATA_MAX_LEN) { > + red_printf("Too much SASL data %d", sasl->len); > + reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA); > + reds_link_free(link); > + return; > + } > + > + if (sasl->len == 0) { > + reds_handle_auth_sasl_start(opaque); > + return; > + } > + > + sasl->data = spice_realloc(sasl->data, sasl->len); > + obj->now = (uint8_t *)sasl->data; > + obj->end = obj->now + sasl->len; > + obj->done = reds_handle_auth_sasl_start; > + async_read_handler(0, 0, &link->asyc_read); > +} > + > +static void reds_handle_auth_mechname(void *opaque) > +{ > + RedLinkInfo *link = (RedLinkInfo *)opaque; > + AsyncRead *obj = &link->asyc_read; > + RedsSASLContext *sasl = &link->stream->sasl; > + > + sasl->mechname[sasl->len] = '\0'; > + red_printf("Got client mechname '%s' check against '%s'", > + sasl->mechname, sasl->mechlist); > + > + if (strncmp(sasl->mechlist, sasl->mechname, sasl->len) == 0) { > + if (sasl->mechlist[sasl->len] != '\0' && > + sasl->mechlist[sasl->len] != ',') { > + red_printf("One %d", sasl->mechlist[sasl->len]); > + reds_link_free(link); > + return; > + } > + } else { > + char *offset = strstr(sasl->mechlist, sasl->mechname); > + red_printf("Two %p", offset); > + if (!offset) { > + reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA); > + return; > + } > + red_printf("Two '%s'", offset); > + if (offset[-1] != ',' || > + (offset[sasl->len] != '\0'&& > + offset[sasl->len] != ',')) { > + reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA); > + return; > + } > + } > + > + free(sasl->mechlist); > + sasl->mechlist = strdup(sasl->mechname); > + > + red_printf("Validated mechname '%s'", sasl->mechname); > + > + obj->now = (uint8_t *)&sasl->len; > + obj->end = obj->now + sizeof(uint32_t); > + obj->done = reds_handle_auth_startlen; > + async_read_handler(0, 0, &link->asyc_read); > + > + return; > +} > + > +static void reds_handle_auth_mechlen(void *opaque) > +{ > + RedLinkInfo *link = (RedLinkInfo *)opaque; > + AsyncRead *obj = &link->asyc_read; > + RedsSASLContext *sasl = &link->stream->sasl; > + > + if (sasl->len < 1 || sasl->len > 100) { > + red_printf("Got client mechname len %d", sasl->len); "Got bad client mechname len %d" FTFY. > + reds_link_free(link); > + return; > + } > + > + sasl->mechname = spice_malloc(sasl->len + 1); > + > + red_printf("Wait for client mechname"); > + obj->now = (uint8_t *)sasl->mechname; > + obj->end = obj->now + sasl->len; > + obj->done = reds_handle_auth_mechname; > + async_read_handler(0, 0, &link->asyc_read); > +} > + > +static void reds_start_auth_sasl(RedLinkInfo *link) > +{ > + const char *mechlist = NULL; > + sasl_security_properties_t secprops; > + int err; > + char *localAddr, *remoteAddr; > + int mechlistlen; > + AsyncRead *obj = &link->asyc_read; > + RedsSASLContext *sasl = &link->stream->sasl; > + > + /* Get local & remote client addresses in form IPADDR;PORT */ > + if (!(localAddr = addr_to_string("%s;%s", &link->stream->info.laddr, > link->stream->info.llen))) > + goto error; > + > + if (!(remoteAddr = addr_to_string("%s;%s", &link->stream->info.paddr, > link->stream->info.plen))) { > + free(localAddr); > + goto error; > + } > + > + err = sasl_server_new("spice", > + NULL, /* FQDN - just delegates to gethostname */ > + NULL, /* User realm */ > + localAddr, > + remoteAddr, > + NULL, /* Callbacks, not needed */ > + SASL_SUCCESS_DATA, > + &sasl->conn); > + free(localAddr); > + free(remoteAddr); > + localAddr = remoteAddr = NULL; > + > + if (err != SASL_OK) { > + red_printf("sasl context setup failed %d (%s)", > + err, sasl_errstring(err, NULL, NULL)); > + sasl->conn = NULL; > + goto error; > + } > + > + /* Inform SASL that we've got an external SSF layer from TLS */ > + if (link->stream->ssl) { > + sasl_ssf_t ssf; > + > + ssf = SSL_get_cipher_bits(link->stream->ssl, NULL); > + err = sasl_setprop(sasl->conn, SASL_SSF_EXTERNAL, &ssf); > + if (err != SASL_OK) { > + red_printf("cannot set SASL external SSF %d (%s)", > + err, sasl_errstring(err, NULL, NULL)); > + sasl_dispose(&sasl->conn); > + sasl->conn = NULL; > + goto error; > + } > + } else > + sasl->wantSSF = 1; Add {}. > + > + memset(&secprops, 0, sizeof secprops); > + /* Inform SASL that we've got an external SSF layer from TLS */ > + if (link->stream->ssl) { > + /* If we've got TLS (or UNIX domain sock), we don't care about SSF */ > + secprops.min_ssf = 0; > + secprops.max_ssf = 0; > + secprops.maxbufsize = 8192; > + secprops.security_flags = 0; > + } else { > + /* Plain TCP, better get an SSF layer */ > + secprops.min_ssf = 56; /* Good enough to require kerberos */ > + secprops.max_ssf = 100000; /* Arbitrary big number */ > + secprops.maxbufsize = 8192; > + /* Forbid any anonymous or trivially crackable auth */ > + secprops.security_flags = > + SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT; > + } > + > + err = sasl_setprop(sasl->conn, SASL_SEC_PROPS, &secprops); > + if (err != SASL_OK) { > + red_printf("cannot set SASL security props %d (%s)", > + err, sasl_errstring(err, NULL, NULL)); > + sasl_dispose(&sasl->conn); > + sasl->conn = NULL; > + goto error; > + } > + > + err = sasl_listmech(sasl->conn, > + NULL, /* Don't need to set user */ > + "", /* Prefix */ > + ",", /* Separator */ > + "", /* Suffix */ > + &mechlist, > + NULL, > + NULL); > + if (err != SASL_OK) { > + red_printf("cannot list SASL mechanisms %d (%s)", > + err, sasl_errdetail(sasl->conn)); > + sasl_dispose(&sasl->conn); > + sasl->conn = NULL; > + goto error; > + } > + red_printf("Available mechanisms for client: '%s'", mechlist); > + > + sasl->mechlist = strdup(mechlist); > + > + mechlistlen = strlen(mechlist); > + if (!sync_write(link->stream, &mechlistlen, sizeof(uint32_t)) > + || !sync_write(link->stream, sasl->mechlist, mechlistlen)) { > + red_printf("SASL mechanisms write error"); > + goto error; > + } > + > + red_printf("Wait for client mechname length"); > + obj->now = (uint8_t *)&sasl->len; > + obj->end = obj->now + sizeof(uint32_t); > + obj->done = reds_handle_auth_mechlen; > + async_read_handler(0, 0, &link->asyc_read); > + > + return; > + > +error: > + reds_link_free(link); > + return; > +} > +#endif > + > static void reds_handle_auth_mechanism(void *opaque) > { > RedLinkInfo *link = (RedLinkInfo *)opaque; > > red_printf("Auth method: %d", link->auth_mechanism.auth_mechanism); > > - if (link->auth_mechanism.auth_mechanism == SPICE_COMMON_CAP_AUTH_SPICE) { > + if (link->auth_mechanism.auth_mechanism == SPICE_COMMON_CAP_AUTH_SPICE > + && !sasl_enabled > + ) { > reds_get_spice_ticket(link); > +#if HAVE_SASL > + } else if (link->auth_mechanism.auth_mechanism == > SPICE_COMMON_CAP_AUTH_SASL) { > + red_printf("Starting SASL"); > + reds_start_auth_sasl(link); > +#endif > } else { > red_printf("Unknown auth method, disconnecting"); > + if (sasl_enabled) > + red_printf("Your client doesn't handle SASL?"); > reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA); > reds_link_free(link); > } > @@ -1784,6 +2404,11 @@ static void reds_handle_read_link_done(void *opaque) > } > > if (!auth_selection) { > + if (sasl_enabled) { > + red_printf("SASL enabled, but peer supports only spice > authentication"); > + reds_send_link_error(link, SPICE_LINK_ERR_VERSION_MISMATCH); > + return; > + } > red_printf("Peer doesn't support AUTH selection"); > reds_get_spice_ticket(link); > } else { > @@ -2846,6 +3471,16 @@ static int do_spice_init(SpiceCoreInterface > *core_interface) > if (reds->secure_listen_socket != -1) { > reds_init_ssl(); > } > +#if HAVE_SASL > + int saslerr; > + if ((saslerr = sasl_server_init(NULL, sasl_appname ? > + sasl_appname : "spice")) != SASL_OK) { > + red_error("Failed to initialize SASL auth %s", > + sasl_errstring(saslerr, NULL, NULL)); > + goto err; > + } > +#endif > + > reds->main_channel = NULL; > inputs_init(); > > @@ -2939,6 +3574,29 @@ __visible__ int spice_server_set_noauth(SpiceServer *s) > return 0; > } > > +__visible__ int spice_server_set_sasl(SpiceServer *s, int enabled) > +{ > + ASSERT(reds == s); > +#if HAVE_SASL > + sasl_enabled = enabled; > + return 0; > +#else > + return -1; > +#endif > +} > + > +__visible__ int spice_server_set_sasl_appname(SpiceServer *s, const char > *appname) > +{ > + ASSERT(reds == s); > +#if HAVE_SASL > + free(sasl_appname); > + sasl_appname = strdup(appname); > + return 0; > +#else > + return -1; > +#endif > +} > + > __visible__ int spice_server_set_ticket(SpiceServer *s, > const char *passwd, int lifetime, > int fail_if_connected, > @@ -3214,12 +3872,30 @@ __visible__ int > spice_server_migrate_switch(SpiceServer *s) > > ssize_t reds_stream_read(RedsStream *s, void *buf, size_t nbyte) > { > - return s->read(s, buf, nbyte); > + ssize_t ret; > + > +#if HAVE_SASL > + if (s->sasl.conn && s->sasl.runSSF) {} > + ret = reds_stream_sasl_read(s, buf, nbyte); > + else {} > +#endif > + ret = s->read(s, buf, nbyte); > + > + return ret; > } > > ssize_t reds_stream_write(RedsStream *s, const void *buf, size_t nbyte) > { > - return s->write(s, buf, nbyte); > + ssize_t ret; > + > +#if HAVE_SASL > + if (s->sasl.conn && s->sasl.runSSF) > + ret = reds_stream_sasl_write(s, buf, nbyte); {} > + else > +#endif > + ret = s->write(s, buf, nbyte); {} > + Wouldn't this be nicer using just a callback? (like olden times) Well, I don't care to write that patch, so I don't mind if this stays. > + return ret; > } > > ssize_t reds_stream_writev(RedsStream *s, const struct iovec *iov, int > iovcnt) > @@ -3248,6 +3924,20 @@ void reds_stream_free(RedsStream *s) > > spice_channel_event(&s->info, SPICE_CHANNEL_EVENT_DISCONNECTED); > > +#if HAVE_SASL > + if (s->sasl.conn) { > + s->sasl.runSSF = s->sasl.wantSSF = 0; > + s->sasl.len = 0; > + s->sasl.encodedLength = s->sasl.encodedOffset = 0; > + s->sasl.encoded = NULL; > + free(s->sasl.mechlist); > + free(s->sasl.mechname); > + s->sasl.mechlist = NULL; > + sasl_dispose(&s->sasl.conn); > + s->sasl.conn = NULL; > + } > +#endif > + > if (s->ssl) > SSL_free(s->ssl);S {} > > diff --git a/server/reds.h b/server/reds.h > index f0276b1..ff015b2 100644 > --- a/server/reds.h > +++ b/server/reds.h > @@ -18,10 +18,16 @@ > #ifndef _H_REDS > #define _H_REDS > > +#include "config.h" > + > #include <stdint.h> > #include <openssl/ssl.h> > #include <sys/uio.h> > #include <spice/vd_agent.h> > +#if HAVE_SASL > +#include <sasl/sasl.h> > +#endif > + > #include "common/marshaller.h" > #include "common/messages.h" > #include "spice.h" > @@ -30,6 +36,35 @@ > > typedef struct RedsStream RedsStream; > > +#if HAVE_SASL > +typedef struct RedsSASLContext { So you use Context here after removing it from RedsStream?? How about just RedsSASL? > + sasl_conn_t *conn; > + > + /* If we want to negotiate an SSF layer with client */ > + int wantSSF :1; > + /* If we are now running the SSF layer */ > + int runSSF :1; > + > + /* > + * Buffering encoded data to allow more clear data > + * to be stuffed onto the output buffer > + */ > + const uint8_t *encoded; > + unsigned int encodedLength; > + unsigned int encodedOffset; > + > + SpiceBuffer inbuffer; > + > + char *username; > + char *mechlist; > + char *mechname; > + > + /* temporary data during authentication */ > + unsigned int len; > + char *data; > +} RedsSASLContext; > +#endif > + > struct RedsStream { > int socket; > SpiceWatch *watch; > @@ -39,6 +74,10 @@ struct RedsStream { > int shutdown; > SSL *ssl; > > +#if HAVE_SASL > + RedsSASLContext sasl; > +#endif > + > SpiceChannelEventInfo info; > > /* private */ > diff --git a/server/spice.h b/server/spice.h > index 6fb22a4..7e85ad7 100644 > --- a/server/spice.h > +++ b/server/spice.h > @@ -374,6 +374,8 @@ int spice_server_set_compat_version(SpiceServer *s, > int spice_server_set_port(SpiceServer *s, int port); > void spice_server_set_addr(SpiceServer *s, const char *addr, int flags); > int spice_server_set_noauth(SpiceServer *s); > +int spice_server_set_sasl(SpiceServer *s, int enabled); > +int spice_server_set_sasl_appname(SpiceServer *s, const char *appname); > int spice_server_set_ticket(SpiceServer *s, const char *passwd, int lifetime, > int fail_if_connected, int > disconnect_if_connected); > int spice_server_set_tls(SpiceServer *s, int port, > -- > 1.7.4 > > _______________________________________________ > Spice-devel mailing list > [email protected] > http://lists.freedesktop.org/mailman/listinfo/spice-devel _______________________________________________ Spice-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/spice-devel
