libvirt/src/rpc/virnetsaslcontext.c

718 lines
20 KiB
C
Raw Normal View History

/*
* virnetsaslcontext.c: SASL encryption/auth handling
*
maint: don't permit format strings without % Any time we have a string with no % passed through gettext, a translator can inject a % to cause a stack overread. When there is nothing to format, it's easier to ask for a string that cannot be used as a formatter, by using a trivial "%s" format instead. In the past, we have used --disable-nls to catch some of the offenders, but that doesn't get run very often, and many more uses have crept in. Syntax check to the rescue! The syntax check can catch uses such as virReportError(code, _("split " "string")); by using a sed script to fold context lines into one pattern space before checking for a string without %. This patch is just mechanical insertion of %s; there are probably several messages touched by this patch where we would be better off giving the user more information than a fixed string. * cfg.mk (sc_prohibit_diagnostic_without_format): New rule. * src/datatypes.c (virUnrefConnect, virGetDomain) (virUnrefDomain, virGetNetwork, virUnrefNetwork, virGetInterface) (virUnrefInterface, virGetStoragePool, virUnrefStoragePool) (virGetStorageVol, virUnrefStorageVol, virGetNodeDevice) (virGetSecret, virUnrefSecret, virGetNWFilter, virUnrefNWFilter) (virGetDomainSnapshot, virUnrefDomainSnapshot): Add %s wrapper. * src/lxc/lxc_driver.c (lxcDomainSetBlkioParameters) (lxcDomainGetBlkioParameters): Likewise. * src/conf/domain_conf.c (virSecurityDeviceLabelDefParseXML) (virDomainDiskDefParseXML, virDomainGraphicsDefParseXML): Likewise. * src/conf/network_conf.c (virNetworkDNSHostsDefParseXML) (virNetworkDefParseXML): Likewise. * src/conf/nwfilter_conf.c (virNWFilterIsValidChainName): Likewise. * src/conf/nwfilter_params.c (virNWFilterVarValueCreateSimple) (virNWFilterVarAccessParse): Likewise. * src/libvirt.c (virDomainSave, virDomainSaveFlags) (virDomainRestore, virDomainRestoreFlags) (virDomainSaveImageGetXMLDesc, virDomainSaveImageDefineXML) (virDomainCoreDump, virDomainGetXMLDesc) (virDomainMigrateVersion1, virDomainMigrateVersion2) (virDomainMigrateVersion3, virDomainMigrate, virDomainMigrate2) (virStreamSendAll, virStreamRecvAll) (virDomainSnapshotGetXMLDesc): Likewise. * src/nwfilter/nwfilter_dhcpsnoop.c (virNWFilterSnoopReqLeaseDel) (virNWFilterDHCPSnoopReq): Likewise. * src/openvz/openvz_driver.c (openvzUpdateDevice): Likewise. * src/openvz/openvz_util.c (openvzKBPerPages): Likewise. * src/qemu/qemu_cgroup.c (qemuSetupCgroup): Likewise. * src/qemu/qemu_command.c (qemuBuildHubDevStr, qemuBuildChrChardevStr) (qemuBuildCommandLine): Likewise. * src/qemu/qemu_driver.c (qemuDomainGetPercpuStats): Likewise. * src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise. * src/rpc/virnetsaslcontext.c (virNetSASLSessionGetIdentity): Likewise. * src/rpc/virnetsocket.c (virNetSocketNewConnectUNIX) (virNetSocketSendFD, virNetSocketRecvFD): Likewise. * src/storage/storage_backend_disk.c (virStorageBackendDiskBuildPool): Likewise. * src/storage/storage_backend_fs.c (virStorageBackendFileSystemProbe) (virStorageBackendFileSystemBuild): Likewise. * src/storage/storage_backend_rbd.c (virStorageBackendRBDOpenRADOSConn): Likewise. * src/storage/storage_driver.c (storageVolumeResize): Likewise. * src/test/test_driver.c (testInterfaceChangeBegin) (testInterfaceChangeCommit, testInterfaceChangeRollback): Likewise. * src/vbox/vbox_tmpl.c (vboxListAllDomains): Likewise. * src/xenxs/xen_sxpr.c (xenFormatSxprDisk, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetUUID, xenFormatXMDisk) (xenFormatXM): Likewise.
2012-07-23 20:33:08 +00:00
* Copyright (C) 2010-2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <fnmatch.h>
#include "virnetsaslcontext.h"
#include "virnetmessage.h"
#include "virterror_internal.h"
#include "memory.h"
#include "threads.h"
#include "logging.h"
#define VIR_FROM_THIS VIR_FROM_RPC
struct _virNetSASLContext {
virObject object;
virMutex lock;
const char *const*usernameWhitelist;
};
struct _virNetSASLSession {
virObject object;
virMutex lock;
sasl_conn_t *conn;
size_t maxbufsize;
};
static virClassPtr virNetSASLContextClass;
static virClassPtr virNetSASLSessionClass;
static void virNetSASLContextDispose(void *obj);
static void virNetSASLSessionDispose(void *obj);
static int virNetSASLContextOnceInit(void)
{
if (!(virNetSASLContextClass = virClassNew("virNetSASLContext",
sizeof(virNetSASLContext),
virNetSASLContextDispose)))
return -1;
if (!(virNetSASLSessionClass = virClassNew("virNetSASLSession",
sizeof(virNetSASLSession),
virNetSASLSessionDispose)))
return -1;
return 0;
}
VIR_ONCE_GLOBAL_INIT(virNetSASLContext)
virNetSASLContextPtr virNetSASLContextNewClient(void)
{
virNetSASLContextPtr ctxt;
int err;
if (virNetSASLContextInitialize() < 0)
return NULL;
err = sasl_client_init(NULL);
if (err != SASL_OK) {
virReportError(VIR_ERR_AUTH_FAILED,
_("failed to initialize SASL library: %d (%s)"),
err, sasl_errstring(err, NULL, NULL));
return NULL;
}
if (!(ctxt = virObjectNew(virNetSASLContextClass)))
return NULL;
if (virMutexInit(&ctxt->lock) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Failed to initialized mutex"));
VIR_FREE(ctxt);
return NULL;
}
return ctxt;
}
virNetSASLContextPtr virNetSASLContextNewServer(const char *const*usernameWhitelist)
{
virNetSASLContextPtr ctxt;
int err;
if (virNetSASLContextInitialize() < 0)
return NULL;
err = sasl_server_init(NULL, "libvirt");
if (err != SASL_OK) {
virReportError(VIR_ERR_AUTH_FAILED,
_("failed to initialize SASL library: %d (%s)"),
err, sasl_errstring(err, NULL, NULL));
return NULL;
}
if (!(ctxt = virObjectNew(virNetSASLContextClass)))
return NULL;
if (virMutexInit(&ctxt->lock) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Failed to initialized mutex"));
VIR_FREE(ctxt);
return NULL;
}
ctxt->usernameWhitelist = usernameWhitelist;
return ctxt;
}
int virNetSASLContextCheckIdentity(virNetSASLContextPtr ctxt,
const char *identity)
{
const char *const*wildcards;
int ret = -1;
virMutexLock(&ctxt->lock);
/* If the list is not set, allow any DN. */
wildcards = ctxt->usernameWhitelist;
if (!wildcards) {
ret = 1; /* No ACL, allow all */
goto cleanup;
}
while (*wildcards) {
int rv = fnmatch (*wildcards, identity, 0);
if (rv == 0) {
ret = 1;
goto cleanup; /* Succesful match */
}
if (rv != FNM_NOMATCH) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Malformed TLS whitelist regular expression '%s'"),
*wildcards);
goto cleanup;
}
wildcards++;
}
/* Denied */
VIR_ERROR(_("SASL client %s not allowed in whitelist"), identity);
/* This is the most common error: make it informative. */
virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
_("Client's username is not on the list of allowed clients"));
ret = 0;
cleanup:
virMutexUnlock(&ctxt->lock);
return ret;
}
void virNetSASLContextDispose(void *obj)
{
virNetSASLContextPtr ctxt = obj;
virMutexDestroy(&ctxt->lock);
}
virNetSASLSessionPtr virNetSASLSessionNewClient(virNetSASLContextPtr ctxt ATTRIBUTE_UNUSED,
const char *service,
const char *hostname,
const char *localAddr,
const char *remoteAddr,
const sasl_callback_t *cbs)
{
virNetSASLSessionPtr sasl = NULL;
int err;
if (!(sasl = virObjectNew(virNetSASLSessionClass)))
return NULL;
if (virMutexInit(&sasl->lock) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Failed to initialized mutex"));
VIR_FREE(sasl);
return NULL;
}
/* Arbitrary size for amount of data we can encode in a single block */
sasl->maxbufsize = 1 << 16;
err = sasl_client_new(service,
hostname,
localAddr,
remoteAddr,
cbs,
SASL_SUCCESS_DATA,
&sasl->conn);
if (err != SASL_OK) {
virReportError(VIR_ERR_AUTH_FAILED,
_("Failed to create SASL client context: %d (%s)"),
err, sasl_errstring(err, NULL, NULL));
goto cleanup;
}
return sasl;
cleanup:
virObjectUnref(sasl);
return NULL;
}
virNetSASLSessionPtr virNetSASLSessionNewServer(virNetSASLContextPtr ctxt ATTRIBUTE_UNUSED,
const char *service,
const char *localAddr,
const char *remoteAddr)
{
virNetSASLSessionPtr sasl = NULL;
int err;
if (!(sasl = virObjectNew(virNetSASLSessionClass)))
return NULL;
if (virMutexInit(&sasl->lock) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Failed to initialized mutex"));
VIR_FREE(sasl);
return NULL;
}
/* Arbitrary size for amount of data we can encode in a single block */
sasl->maxbufsize = 1 << 16;
err = sasl_server_new(service,
NULL,
NULL,
localAddr,
remoteAddr,
NULL,
SASL_SUCCESS_DATA,
&sasl->conn);
if (err != SASL_OK) {
virReportError(VIR_ERR_AUTH_FAILED,
_("Failed to create SASL client context: %d (%s)"),
err, sasl_errstring(err, NULL, NULL));
goto cleanup;
}
return sasl;
cleanup:
virObjectUnref(sasl);
return NULL;
}
int virNetSASLSessionExtKeySize(virNetSASLSessionPtr sasl,
int ssf)
{
int err;
int ret = -1;
virMutexLock(&sasl->lock);
err = sasl_setprop(sasl->conn, SASL_SSF_EXTERNAL, &ssf);
if (err != SASL_OK) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot set external SSF %d (%s)"),
err, sasl_errstring(err, NULL, NULL));
goto cleanup;
}
ret = 0;
cleanup:
virMutexUnlock(&sasl->lock);
return ret;
}
const char *virNetSASLSessionGetIdentity(virNetSASLSessionPtr sasl)
{
const void *val = NULL;
int err;
virMutexLock(&sasl->lock);
err = sasl_getprop(sasl->conn, SASL_USERNAME, &val);
if (err != SASL_OK) {
virReportError(VIR_ERR_AUTH_FAILED,
_("cannot query SASL username on connection %d (%s)"),
err, sasl_errstring(err, NULL, NULL));
val = NULL;
goto cleanup;
}
if (val == NULL) {
maint: don't permit format strings without % Any time we have a string with no % passed through gettext, a translator can inject a % to cause a stack overread. When there is nothing to format, it's easier to ask for a string that cannot be used as a formatter, by using a trivial "%s" format instead. In the past, we have used --disable-nls to catch some of the offenders, but that doesn't get run very often, and many more uses have crept in. Syntax check to the rescue! The syntax check can catch uses such as virReportError(code, _("split " "string")); by using a sed script to fold context lines into one pattern space before checking for a string without %. This patch is just mechanical insertion of %s; there are probably several messages touched by this patch where we would be better off giving the user more information than a fixed string. * cfg.mk (sc_prohibit_diagnostic_without_format): New rule. * src/datatypes.c (virUnrefConnect, virGetDomain) (virUnrefDomain, virGetNetwork, virUnrefNetwork, virGetInterface) (virUnrefInterface, virGetStoragePool, virUnrefStoragePool) (virGetStorageVol, virUnrefStorageVol, virGetNodeDevice) (virGetSecret, virUnrefSecret, virGetNWFilter, virUnrefNWFilter) (virGetDomainSnapshot, virUnrefDomainSnapshot): Add %s wrapper. * src/lxc/lxc_driver.c (lxcDomainSetBlkioParameters) (lxcDomainGetBlkioParameters): Likewise. * src/conf/domain_conf.c (virSecurityDeviceLabelDefParseXML) (virDomainDiskDefParseXML, virDomainGraphicsDefParseXML): Likewise. * src/conf/network_conf.c (virNetworkDNSHostsDefParseXML) (virNetworkDefParseXML): Likewise. * src/conf/nwfilter_conf.c (virNWFilterIsValidChainName): Likewise. * src/conf/nwfilter_params.c (virNWFilterVarValueCreateSimple) (virNWFilterVarAccessParse): Likewise. * src/libvirt.c (virDomainSave, virDomainSaveFlags) (virDomainRestore, virDomainRestoreFlags) (virDomainSaveImageGetXMLDesc, virDomainSaveImageDefineXML) (virDomainCoreDump, virDomainGetXMLDesc) (virDomainMigrateVersion1, virDomainMigrateVersion2) (virDomainMigrateVersion3, virDomainMigrate, virDomainMigrate2) (virStreamSendAll, virStreamRecvAll) (virDomainSnapshotGetXMLDesc): Likewise. * src/nwfilter/nwfilter_dhcpsnoop.c (virNWFilterSnoopReqLeaseDel) (virNWFilterDHCPSnoopReq): Likewise. * src/openvz/openvz_driver.c (openvzUpdateDevice): Likewise. * src/openvz/openvz_util.c (openvzKBPerPages): Likewise. * src/qemu/qemu_cgroup.c (qemuSetupCgroup): Likewise. * src/qemu/qemu_command.c (qemuBuildHubDevStr, qemuBuildChrChardevStr) (qemuBuildCommandLine): Likewise. * src/qemu/qemu_driver.c (qemuDomainGetPercpuStats): Likewise. * src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise. * src/rpc/virnetsaslcontext.c (virNetSASLSessionGetIdentity): Likewise. * src/rpc/virnetsocket.c (virNetSocketNewConnectUNIX) (virNetSocketSendFD, virNetSocketRecvFD): Likewise. * src/storage/storage_backend_disk.c (virStorageBackendDiskBuildPool): Likewise. * src/storage/storage_backend_fs.c (virStorageBackendFileSystemProbe) (virStorageBackendFileSystemBuild): Likewise. * src/storage/storage_backend_rbd.c (virStorageBackendRBDOpenRADOSConn): Likewise. * src/storage/storage_driver.c (storageVolumeResize): Likewise. * src/test/test_driver.c (testInterfaceChangeBegin) (testInterfaceChangeCommit, testInterfaceChangeRollback): Likewise. * src/vbox/vbox_tmpl.c (vboxListAllDomains): Likewise. * src/xenxs/xen_sxpr.c (xenFormatSxprDisk, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetUUID, xenFormatXMDisk) (xenFormatXM): Likewise.
2012-07-23 20:33:08 +00:00
virReportError(VIR_ERR_AUTH_FAILED, "%s",
_("no client username was found"));
goto cleanup;
}
VIR_DEBUG("SASL client username %s", (const char *)val);
cleanup:
virMutexUnlock(&sasl->lock);
return (const char*)val;
}
int virNetSASLSessionGetKeySize(virNetSASLSessionPtr sasl)
{
int err;
int ssf;
const void *val;
virMutexLock(&sasl->lock);
err = sasl_getprop(sasl->conn, SASL_SSF, &val);
if (err != SASL_OK) {
virReportError(VIR_ERR_AUTH_FAILED,
_("cannot query SASL ssf on connection %d (%s)"),
err, sasl_errstring(err, NULL, NULL));
ssf = -1;
goto cleanup;
}
ssf = *(const int *)val;
cleanup:
virMutexUnlock(&sasl->lock);
return ssf;
}
int virNetSASLSessionSecProps(virNetSASLSessionPtr sasl,
int minSSF,
int maxSSF,
bool allowAnonymous)
{
sasl_security_properties_t secprops;
int err;
int ret = -1;
VIR_DEBUG("minSSF=%d maxSSF=%d allowAnonymous=%d maxbufsize=%zu",
minSSF, maxSSF, allowAnonymous, sasl->maxbufsize);
virMutexLock(&sasl->lock);
memset(&secprops, 0, sizeof(secprops));
secprops.min_ssf = minSSF;
secprops.max_ssf = maxSSF;
secprops.maxbufsize = sasl->maxbufsize;
secprops.security_flags = allowAnonymous ? 0 :
SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
err = sasl_setprop(sasl->conn, SASL_SEC_PROPS, &secprops);
if (err != SASL_OK) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot set security props %d (%s)"),
err, sasl_errstring(err, NULL, NULL));
goto cleanup;
}
ret = 0;
cleanup:
virMutexUnlock(&sasl->lock);
return ret;
}
static int virNetSASLSessionUpdateBufSize(virNetSASLSessionPtr sasl)
{
union {
unsigned *maxbufsize;
const void *ptr;
} u;
int err;
err = sasl_getprop(sasl->conn, SASL_MAXOUTBUF, &u.ptr);
if (err != SASL_OK) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot get security props %d (%s)"),
err, sasl_errstring(err, NULL, NULL));
return -1;
}
VIR_DEBUG("Negotiated bufsize is %u vs requested size %zu",
*u.maxbufsize, sasl->maxbufsize);
sasl->maxbufsize = *u.maxbufsize;
return 0;
}
char *virNetSASLSessionListMechanisms(virNetSASLSessionPtr sasl)
{
const char *mechlist;
char *ret = NULL;
int err;
virMutexLock(&sasl->lock);
err = sasl_listmech(sasl->conn,
NULL, /* Don't need to set user */
"", /* Prefix */
",", /* Separator */
"", /* Suffix */
&mechlist,
NULL,
NULL);
if (err != SASL_OK) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot list SASL mechanisms %d (%s)"),
err, sasl_errdetail(sasl->conn));
goto cleanup;
}
if (!(ret = strdup(mechlist))) {
virReportOOMError();
goto cleanup;
}
cleanup:
virMutexUnlock(&sasl->lock);
return ret;
}
int virNetSASLSessionClientStart(virNetSASLSessionPtr sasl,
const char *mechlist,
sasl_interact_t **prompt_need,
const char **clientout,
size_t *clientoutlen,
const char **mech)
{
unsigned outlen = 0;
int err;
int ret = -1;
VIR_DEBUG("sasl=%p mechlist=%s prompt_need=%p clientout=%p clientoutlen=%p mech=%p",
sasl, mechlist, prompt_need, clientout, clientoutlen, mech);
virMutexLock(&sasl->lock);
err = sasl_client_start(sasl->conn,
mechlist,
prompt_need,
clientout,
&outlen,
mech);
*clientoutlen = outlen;
switch (err) {
case SASL_OK:
if (virNetSASLSessionUpdateBufSize(sasl) < 0)
goto cleanup;
ret = VIR_NET_SASL_COMPLETE;
break;
case SASL_CONTINUE:
ret = VIR_NET_SASL_CONTINUE;
break;
case SASL_INTERACT:
ret = VIR_NET_SASL_INTERACT;
break;
default:
virReportError(VIR_ERR_AUTH_FAILED,
_("Failed to start SASL negotiation: %d (%s)"),
err, sasl_errdetail(sasl->conn));
break;
}
cleanup:
virMutexUnlock(&sasl->lock);
return ret;
}
int virNetSASLSessionClientStep(virNetSASLSessionPtr sasl,
const char *serverin,
size_t serverinlen,
sasl_interact_t **prompt_need,
const char **clientout,
size_t *clientoutlen)
{
unsigned inlen = serverinlen;
unsigned outlen = 0;
int err;
int ret = -1;
VIR_DEBUG("sasl=%p serverin=%s serverinlen=%zu prompt_need=%p clientout=%p clientoutlen=%p",
sasl, serverin, serverinlen, prompt_need, clientout, clientoutlen);
virMutexLock(&sasl->lock);
err = sasl_client_step(sasl->conn,
serverin,
inlen,
prompt_need,
clientout,
&outlen);
*clientoutlen = outlen;
switch (err) {
case SASL_OK:
if (virNetSASLSessionUpdateBufSize(sasl) < 0)
goto cleanup;
ret = VIR_NET_SASL_COMPLETE;
break;
case SASL_CONTINUE:
ret = VIR_NET_SASL_CONTINUE;
break;
case SASL_INTERACT:
ret = VIR_NET_SASL_INTERACT;
break;
default:
virReportError(VIR_ERR_AUTH_FAILED,
_("Failed to step SASL negotiation: %d (%s)"),
err, sasl_errdetail(sasl->conn));
break;
}
cleanup:
virMutexUnlock(&sasl->lock);
return ret;
}
int virNetSASLSessionServerStart(virNetSASLSessionPtr sasl,
const char *mechname,
const char *clientin,
size_t clientinlen,
const char **serverout,
size_t *serveroutlen)
{
unsigned inlen = clientinlen;
unsigned outlen = 0;
int err;
int ret = -1;
virMutexLock(&sasl->lock);
err = sasl_server_start(sasl->conn,
mechname,
clientin,
inlen,
serverout,
&outlen);
*serveroutlen = outlen;
switch (err) {
case SASL_OK:
if (virNetSASLSessionUpdateBufSize(sasl) < 0)
goto cleanup;
ret = VIR_NET_SASL_COMPLETE;
break;
case SASL_CONTINUE:
ret = VIR_NET_SASL_CONTINUE;
break;
case SASL_INTERACT:
ret = VIR_NET_SASL_INTERACT;
break;
default:
virReportError(VIR_ERR_AUTH_FAILED,
_("Failed to start SASL negotiation: %d (%s)"),
err, sasl_errdetail(sasl->conn));
break;
}
cleanup:
virMutexUnlock(&sasl->lock);
return ret;
}
int virNetSASLSessionServerStep(virNetSASLSessionPtr sasl,
const char *clientin,
size_t clientinlen,
const char **serverout,
size_t *serveroutlen)
{
unsigned inlen = clientinlen;
unsigned outlen = 0;
int err;
int ret = -1;
virMutexLock(&sasl->lock);
err = sasl_server_step(sasl->conn,
clientin,
inlen,
serverout,
&outlen);
*serveroutlen = outlen;
switch (err) {
case SASL_OK:
if (virNetSASLSessionUpdateBufSize(sasl) < 0)
goto cleanup;
ret = VIR_NET_SASL_COMPLETE;
break;
case SASL_CONTINUE:
ret = VIR_NET_SASL_CONTINUE;
break;
case SASL_INTERACT:
ret = VIR_NET_SASL_INTERACT;
break;
default:
virReportError(VIR_ERR_AUTH_FAILED,
_("Failed to start SASL negotiation: %d (%s)"),
err, sasl_errdetail(sasl->conn));
break;
}
cleanup:
virMutexUnlock(&sasl->lock);
return ret;
}
size_t virNetSASLSessionGetMaxBufSize(virNetSASLSessionPtr sasl)
{
size_t ret;
virMutexLock(&sasl->lock);
ret = sasl->maxbufsize;
virMutexUnlock(&sasl->lock);
return ret;
}
ssize_t virNetSASLSessionEncode(virNetSASLSessionPtr sasl,
const char *input,
size_t inputLen,
const char **output,
size_t *outputlen)
{
unsigned inlen = inputLen;
unsigned outlen = 0;
int err;
ssize_t ret = -1;
virMutexLock(&sasl->lock);
if (inputLen > sasl->maxbufsize) {
virReportSystemError(EINVAL,
_("SASL data length %zu too long, max %zu"),
inputLen, sasl->maxbufsize);
goto cleanup;
}
err = sasl_encode(sasl->conn,
input,
inlen,
output,
&outlen);
*outputlen = outlen;
if (err != SASL_OK) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to encode SASL data: %d (%s)"),
err, sasl_errstring(err, NULL, NULL));
goto cleanup;
}
ret = 0;
cleanup:
virMutexUnlock(&sasl->lock);
return ret;
}
ssize_t virNetSASLSessionDecode(virNetSASLSessionPtr sasl,
const char *input,
size_t inputLen,
const char **output,
size_t *outputlen)
{
unsigned inlen = inputLen;
unsigned outlen = 0;
int err;
ssize_t ret = -1;
virMutexLock(&sasl->lock);
if (inputLen > sasl->maxbufsize) {
virReportSystemError(EINVAL,
_("SASL data length %zu too long, max %zu"),
inputLen, sasl->maxbufsize);
goto cleanup;
}
err = sasl_decode(sasl->conn,
input,
inlen,
output,
&outlen);
*outputlen = outlen;
if (err != SASL_OK) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to decode SASL data: %d (%s)"),
err, sasl_errstring(err, NULL, NULL));
goto cleanup;
}
ret = 0;
cleanup:
virMutexUnlock(&sasl->lock);
return ret;
}
void virNetSASLSessionDispose(void *obj)
{
virNetSASLSessionPtr sasl = obj;
if (sasl->conn)
sasl_dispose(&sasl->conn);
virMutexDestroy(&sasl->lock);
}