/* Check DN is on tls_allowed_dn_list. */
static int
-remoteCheckDN (gnutls_x509_crt_t cert)
+remoteCheckDN (const char *dname)
{
- char name[256];
- size_t namesize = sizeof name;
char **wildcards;
- int err;
-
- err = gnutls_x509_crt_get_dn (cert, name, &namesize);
- if (err != 0) {
- VIR_ERROR(_("remoteCheckDN: gnutls_x509_cert_get_dn: %s"),
- gnutls_strerror (err));
- return 0;
- }
/* If the list is not set, allow any DN. */
wildcards = tls_allowed_dn_list;
return 1;
while (*wildcards) {
- if (fnmatch (*wildcards, name, 0) == 0)
+ if (fnmatch (*wildcards, dname, 0) == 0)
return 1;
wildcards++;
}
/* Print the client's DN. */
- DEBUG(_("remoteCheckDN: failed: client DN is %s"), name);
+ DEBUG(_("remoteCheckDN: failed: client DN is %s"), dname);
return 0; // Not found.
}
static int
-remoteCheckCertificate (gnutls_session_t session)
+remoteCheckCertificate(struct qemud_client *client)
{
int ret;
unsigned int status;
const gnutls_datum_t *certs;
unsigned int nCerts, i;
time_t now;
+ char name[256];
+ size_t namesize = sizeof name;
+
+ memset(name, 0, namesize);
- if ((ret = gnutls_certificate_verify_peers2 (session, &status)) < 0){
- VIR_ERROR(_("remoteCheckCertificate: verify failed: %s"),
+ if ((ret = gnutls_certificate_verify_peers2 (client->tlssession, &status)) < 0){
+ VIR_ERROR(_("Failed to verify certificate peers: %s"),
gnutls_strerror (ret));
- return -1;
+ goto authdeny;
}
if (status != 0) {
if (status & GNUTLS_CERT_INVALID)
- VIR_ERROR0(_("remoteCheckCertificate: "
- "the client certificate is not trusted."));
+ VIR_ERROR0(_("The client certificate is not trusted."));
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
- VIR_ERROR0(_("remoteCheckCertificate: the client "
- "certificate has unknown issuer."));
+ VIR_ERROR0(_("The client certificate has unknown issuer."));
if (status & GNUTLS_CERT_REVOKED)
- VIR_ERROR0(_("remoteCheckCertificate: "
- "the client certificate has been revoked."));
+ VIR_ERROR0(_("The client certificate has been revoked."));
#ifndef GNUTLS_1_0_COMPAT
if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
- VIR_ERROR0(_("remoteCheckCertificate: the client certificate"
- " uses an insecure algorithm."));
+ VIR_ERROR0(_("The client certificate uses an insecure algorithm."));
#endif
- return -1;
+ goto authdeny;
}
- if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) {
- VIR_ERROR0(_("remoteCheckCertificate: certificate is not X.509"));
- return -1;
+ if (gnutls_certificate_type_get(client->tlssession) != GNUTLS_CRT_X509) {
+ VIR_ERROR0(_("Only x509 certificates are supported"));
+ goto authdeny;
}
- if (!(certs = gnutls_certificate_get_peers(session, &nCerts))) {
- VIR_ERROR0(_("remoteCheckCertificate: no peers"));
- return -1;
+ if (!(certs = gnutls_certificate_get_peers(client->tlssession, &nCerts))) {
+ VIR_ERROR0(_("The certificate has no peers"));
+ goto authdeny;
}
now = time (NULL);
gnutls_x509_crt_t cert;
if (gnutls_x509_crt_init (&cert) < 0) {
- VIR_ERROR0(_("remoteCheckCertificate: gnutls_x509_crt_init failed"));
- return -1;
+ VIR_ERROR0(_("Unable to initialize certificate"));
+ goto authfail;
}
if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
+ VIR_ERROR0(_("Unable to load certificate"));
gnutls_x509_crt_deinit (cert);
- return -1;
+ goto authfail;
+ }
+
+ if (i == 0) {
+ ret = gnutls_x509_crt_get_dn (cert, name, &namesize);
+ if (ret != 0) {
+ VIR_ERROR(_("Failed to get certificate distinguished name: %s"),
+ gnutls_strerror(ret));
+ gnutls_x509_crt_deinit (cert);
+ goto authfail;
+ }
+
+ if (!remoteCheckDN (name)) {
+ /* This is the most common error: make it informative. */
+ VIR_ERROR0(_("Client's Distinguished Name is not on the list "
+ "of allowed clients (tls_allowed_dn_list). Use "
+ "'certtool -i --infile clientcert.pem' to view the"
+ "Distinguished Name field in the client certificate,"
+ "or run this daemon with --verbose option."));
+ gnutls_x509_crt_deinit (cert);
+ goto authdeny;
+ }
}
if (gnutls_x509_crt_get_expiration_time (cert) < now) {
- VIR_ERROR0(_("remoteCheckCertificate: "
- "the client certificate has expired"));
+ VIR_ERROR0(_("The client certificate has expired"));
gnutls_x509_crt_deinit (cert);
- return -1;
+ goto authdeny;
}
if (gnutls_x509_crt_get_activation_time (cert) > now) {
- VIR_ERROR0(_("remoteCheckCertificate: the client "
- "certificate is not yet activated"));
+ VIR_ERROR0(_("The client certificate is not yet active"));
gnutls_x509_crt_deinit (cert);
- return -1;
- }
-
- if (i == 0) {
- if (!remoteCheckDN (cert)) {
- /* This is the most common error: make it informative. */
- VIR_ERROR0(_("remoteCheckCertificate: client's Distinguished Name is not on the list of allowed clients (tls_allowed_dn_list). Use 'certtool -i --infile clientcert.pem' to view the Distinguished Name field in the client certificate, or run this daemon with --verbose option."));
- gnutls_x509_crt_deinit (cert);
- return -1;
- }
+ goto authdeny;
}
}
return 0;
+
+authdeny:
+ return -1;
+
+authfail:
+ return -1;
}
/* Check the client's access. */
struct qemud_client_message *confirm;
/* Verify client certificate. */
- if (remoteCheckCertificate (client->tlssession) == -1) {
+ if (remoteCheckCertificate (client) == -1) {
VIR_ERROR0(_("remoteCheckCertificate: "
"failed to verify client's certificate"));
if (!tls_no_verify_certificate) return -1;
int fd;
struct sockaddr_storage addr;
socklen_t addrlen = (socklen_t) (sizeof addr);
- struct qemud_client *client;
+ struct qemud_client *client = NULL;
int no_slow_start = 1;
int i;
if (server->nclients >= max_clients) {
VIR_ERROR(_("Too many active clients (%d), dropping connection"), max_clients);
- close(fd);
- return -1;
+ goto error;
}
if (VIR_REALLOC_N(server->clients, server->nclients+1) < 0) {
VIR_ERROR0(_("Out of memory allocating clients"));
- close(fd);
- return -1;
+ goto error;
}
#ifdef __sun
(privs = ucred_getprivset (ucred, PRIV_EFFECTIVE)) == NULL) {
if (ucred != NULL)
ucred_free (ucred);
- close (fd);
- return -1;
+ goto error;
}
if (!priv_ismember (privs, PRIV_VIRT_MANAGE)) {
ucred_free (ucred);
- close (fd);
- return -1;
+ goto error;
}
ucred_free (ucred);
if (virSetCloseExec(fd) < 0 ||
virSetNonBlock(fd) < 0) {
- close(fd);
- return -1;
+ goto error;
}
if (VIR_ALLOC(client) < 0)
- goto cleanup;
+ goto error;
if (virMutexInit(&client->lock) < 0) {
VIR_ERROR0(_("cannot initialize mutex"));
- VIR_FREE(client);
- goto cleanup;
+ goto error;
}
client->magic = QEMUD_CLIENT_MAGIC;
/* Prepare one for packet receive */
if (VIR_ALLOC(client->rx) < 0)
- goto cleanup;
+ goto error;
client->rx->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
pid_t pid;
if (qemudGetSocketIdentity(client->fd, &uid, &pid) < 0)
- goto cleanup;
+ goto error;
/* Client is running as root, so disable auth */
if (uid == 0) {
if (client->type != QEMUD_SOCK_TYPE_TLS) {
/* Plain socket, so prepare to read first message */
if (qemudRegisterClientEvent (server, client) < 0)
- goto cleanup;
+ goto error;
} else {
int ret;
client->tlssession = remoteInitializeTLSSession ();
if (client->tlssession == NULL)
- goto cleanup;
+ goto error;
gnutls_transport_set_ptr (client->tlssession,
(gnutls_transport_ptr_t) (long) fd);
/* Unlikely, but ... Next step is to check the certificate. */
if (remoteCheckAccess (client) == -1)
- goto cleanup;
+ goto error;
/* Handshake & cert check OK, so prepare to read first message */
if (qemudRegisterClientEvent(server, client) < 0)
- goto cleanup;
+ goto error;
} else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
/* Most likely, need to do more handshake data */
client->handshake = 1;
if (qemudRegisterClientEvent (server, client) < 0)
- goto cleanup;
+ goto error;
} else {
VIR_ERROR(_("TLS handshake failed: %s"),
gnutls_strerror (ret));
- goto cleanup;
+ goto error;
}
}
return 0;
- cleanup:
- if (client &&
- client->tlssession) gnutls_deinit (client->tlssession);
+error:
+ if (client) {
+ if (client->tlssession) gnutls_deinit (client->tlssession);
+ if (client)
+ VIR_FREE(client->rx);
+ VIR_FREE(client);
+ }
close (fd);
- if (client)
- VIR_FREE(client->rx);
- VIR_FREE(client);
return -1;
}
/* We asked for an SSF layer, so sanity check that we actually
- * got what we asked for */
+ * got what we asked for
+ * Returns 0 if ok, -1 on error, -2 if rejected
+ */
static int
remoteSASLCheckSSF (struct qemud_client *client,
remote_error *rerr) {
remoteDispatchAuthError(rerr);
sasl_dispose(&client->saslconn);
client->saslconn = NULL;
- return -1;
+ return -2;
}
/* Only setup for read initially, because we're about to send an RPC
return 0;
}
+/*
+ * Returns 0 if ok, -1 on error, -2 if rejected
+ */
static int
remoteSASLCheckAccess (struct qemud_server *server,
struct qemud_client *client,
remoteDispatchAuthError(rerr);
sasl_dispose(&client->saslconn);
client->saslconn = NULL;
- return -1;
+ return -2;
}
if (err == SASL_CONTINUE) {
ret->complete = 0;
} else {
- if (remoteSASLCheckSSF(client, rerr) < 0)
- goto error;
-
/* Check username whitelist ACL */
- if (remoteSASLCheckAccess(server, client, rerr) < 0)
- goto error;
+ if ((err = remoteSASLCheckAccess(server, client, rerr)) < 0 ||
+ (err = remoteSASLCheckSSF(client, rerr)) < 0) {
+ if (err == -2)
+ goto authdeny;
+ else
+ goto authfail;
+ }
REMOTE_DEBUG("Authentication successful %d", client->fd);
ret->complete = 1;
authfail:
remoteDispatchAuthError(rerr);
+ goto error;
+
+authdeny:
+ goto error;
+
error:
virMutexUnlock(&client->lock);
return -1;
if (err == SASL_CONTINUE) {
ret->complete = 0;
} else {
- if (remoteSASLCheckSSF(client, rerr) < 0)
- goto error;
-
/* Check username whitelist ACL */
- if (remoteSASLCheckAccess(server, client, rerr) < 0)
- goto error;
+ if ((err = remoteSASLCheckAccess(server, client, rerr)) < 0 ||
+ (err = remoteSASLCheckSSF(client, rerr)) < 0) {
+ if (err == -2)
+ goto authdeny;
+ else
+ goto authfail;
+ }
REMOTE_DEBUG("Authentication successful %d", client->fd);
ret->complete = 1;
authfail:
remoteDispatchAuthError(rerr);
+ goto error;
+
+authdeny:
+ goto error;
+
error:
virMutexUnlock(&client->lock);
return -1;
void *args ATTRIBUTE_UNUSED,
remote_auth_polkit_ret *ret)
{
- pid_t callerPid;
- uid_t callerUid;
+ pid_t callerPid = -1;
+ uid_t callerUid = -1;
const char *action;
int status = -1;
char pidbuf[50];
+ char ident[100];
int rv;
+ memset(ident, 0, sizeof ident);
+
virMutexLock(&server->lock);
virMutexLock(&client->lock);
virMutexUnlock(&server->lock);
goto authfail;
}
+ rv = snprintf(ident, sizeof ident, "pid:%d,uid:%d", callerPid, callerUid);
+ if (rv < 0 || rv >= sizeof ident) {
+ VIR_ERROR(_("Caller identity was too large %d:%d"), callerPid, callerUid);
+ goto authfail;
+ }
+
if (virRun(pkcheck, &status) < 0) {
VIR_ERROR(_("Cannot invoke %s"), PKCHECK_PATH);
goto authfail;
if (status != 0) {
VIR_ERROR(_("Policy kit denied action %s from pid %d, uid %d, result: %d"),
action, callerPid, callerUid, status);
- goto authfail;
+ goto authdeny;
}
VIR_INFO(_("Policy allowed action %s from pid %d, uid %d"),
action, callerPid, callerUid);
return 0;
authfail:
+ goto error;
+
+authdeny:
+ goto error;
+
+error:
remoteDispatchAuthError(rerr);
virMutexUnlock(&client->lock);
return -1;
PolKitResult pkresult;
DBusError err;
const char *action;
+ char ident[100];
+
+ memset(ident, 0, sizeof ident);
virMutexLock(&server->lock);
virMutexLock(&client->lock);
goto authfail;
}
+ rv = snprintf(ident, sizeof ident, "pid:%d,uid:%d", callerPid, callerUid);
+ if (rv < 0 || rv >= sizeof ident) {
+ VIR_ERROR(_("Caller identity was too large %d:%d"), callerPid, callerUid);
+ goto authfail;
+ }
+
VIR_INFO(_("Checking PID %d running as %d"), callerPid, callerUid);
dbus_error_init(&err);
if (!(pkcaller = polkit_caller_new_from_pid(server->sysbus,
VIR_ERROR(_("Policy kit denied action %s from pid %d, uid %d, result: %s"),
action, callerPid, callerUid,
polkit_result_to_string_representation(pkresult));
- goto authfail;
+ goto authdeny;
}
VIR_INFO(_("Policy allowed action %s from pid %d, uid %d, result %s"),
action, callerPid, callerUid,
return 0;
authfail:
+ goto error;
+
+authdeny:
+ goto error;
+
+error:
remoteDispatchAuthError(rerr);
virMutexUnlock(&client->lock);
return -1;