|
Packit |
fd8b60 |
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
Packit |
fd8b60 |
/* lib/krad/remote.c - Protocol code for libkrad */
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Copyright 2013 Red Hat, Inc. All rights reserved.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
fd8b60 |
* modification, are permitted provided that the following conditions are met:
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* 1. Redistributions of source code must retain the above copyright
|
|
Packit |
fd8b60 |
* notice, this list of conditions and the following disclaimer.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* 2. Redistributions in binary form must reproduce the above copyright
|
|
Packit |
fd8b60 |
* notice, this list of conditions and the following disclaimer in
|
|
Packit |
fd8b60 |
* the documentation and/or other materials provided with the
|
|
Packit |
fd8b60 |
* distribution.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
Packit |
fd8b60 |
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
Packit |
fd8b60 |
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
Packit |
fd8b60 |
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
|
Packit |
fd8b60 |
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
Packit |
fd8b60 |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
Packit |
fd8b60 |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
Packit |
fd8b60 |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
Packit |
fd8b60 |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
Packit |
fd8b60 |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
Packit |
fd8b60 |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include <k5-int.h>
|
|
Packit |
fd8b60 |
#include <k5-queue.h>
|
|
Packit |
fd8b60 |
#include "internal.h"
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include <string.h>
|
|
Packit |
fd8b60 |
#include <unistd.h>
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include <sys/un.h>
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#define FLAGS_NONE VERTO_EV_FLAG_NONE
|
|
Packit |
fd8b60 |
#define FLAGS_READ VERTO_EV_FLAG_IO_READ
|
|
Packit |
fd8b60 |
#define FLAGS_WRITE VERTO_EV_FLAG_IO_WRITE
|
|
Packit |
fd8b60 |
#define FLAGS_BASE VERTO_EV_FLAG_PERSIST | VERTO_EV_FLAG_IO_ERROR
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
K5_TAILQ_HEAD(request_head, request_st);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
typedef struct request_st request;
|
|
Packit |
fd8b60 |
struct request_st {
|
|
Packit |
fd8b60 |
K5_TAILQ_ENTRY(request_st) list;
|
|
Packit |
fd8b60 |
krad_remote *rr;
|
|
Packit |
fd8b60 |
krad_packet *request;
|
|
Packit |
fd8b60 |
krad_cb cb;
|
|
Packit |
fd8b60 |
void *data;
|
|
Packit |
fd8b60 |
verto_ev *timer;
|
|
Packit |
fd8b60 |
int timeout;
|
|
Packit |
fd8b60 |
size_t retries;
|
|
Packit |
fd8b60 |
size_t sent;
|
|
Packit |
fd8b60 |
};
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
struct krad_remote_st {
|
|
Packit |
fd8b60 |
krb5_context kctx;
|
|
Packit |
fd8b60 |
verto_ctx *vctx;
|
|
Packit |
fd8b60 |
int fd;
|
|
Packit |
fd8b60 |
verto_ev *io;
|
|
Packit |
fd8b60 |
char *secret;
|
|
Packit |
fd8b60 |
struct addrinfo *info;
|
|
Packit |
fd8b60 |
struct request_head list;
|
|
Packit |
fd8b60 |
char buffer_[KRAD_PACKET_SIZE_MAX];
|
|
Packit |
fd8b60 |
krb5_data buffer;
|
|
Packit |
fd8b60 |
};
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static void
|
|
Packit |
fd8b60 |
on_io(verto_ctx *ctx, verto_ev *ev);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static void
|
|
Packit |
fd8b60 |
on_timeout(verto_ctx *ctx, verto_ev *ev);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Iterate over the set of outstanding packets. */
|
|
Packit |
fd8b60 |
static const krad_packet *
|
|
Packit |
fd8b60 |
iterator(request **out)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
request *tmp = *out;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (tmp == NULL)
|
|
Packit |
fd8b60 |
return NULL;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*out = K5_TAILQ_NEXT(tmp, list);
|
|
Packit |
fd8b60 |
return tmp->request;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Create a new request. */
|
|
Packit |
fd8b60 |
static krb5_error_code
|
|
Packit |
fd8b60 |
request_new(krad_remote *rr, krad_packet *rqst, int timeout, size_t retries,
|
|
Packit |
fd8b60 |
krad_cb cb, void *data, request **out)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
request *tmp;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
tmp = calloc(1, sizeof(request));
|
|
Packit |
fd8b60 |
if (tmp == NULL)
|
|
Packit |
fd8b60 |
return ENOMEM;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
tmp->rr = rr;
|
|
Packit |
fd8b60 |
tmp->request = rqst;
|
|
Packit |
fd8b60 |
tmp->cb = cb;
|
|
Packit |
fd8b60 |
tmp->data = data;
|
|
Packit |
fd8b60 |
tmp->timeout = timeout;
|
|
Packit |
fd8b60 |
tmp->retries = retries;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*out = tmp;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Finish a request, calling the callback and freeing it. */
|
|
Packit |
fd8b60 |
static inline void
|
|
Packit |
fd8b60 |
request_finish(request *req, krb5_error_code retval,
|
|
Packit |
fd8b60 |
const krad_packet *response)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
if (retval != ETIMEDOUT)
|
|
Packit |
fd8b60 |
K5_TAILQ_REMOVE(&req->rr->list, req, list);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
req->cb(retval, req->request, response, req->data);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (retval != ETIMEDOUT) {
|
|
Packit |
fd8b60 |
krad_packet_free(req->request);
|
|
Packit |
fd8b60 |
verto_del(req->timer);
|
|
Packit |
fd8b60 |
free(req);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Start the timeout timer for the request. */
|
|
Packit |
fd8b60 |
static krb5_error_code
|
|
Packit |
fd8b60 |
request_start_timer(request *r, verto_ctx *vctx)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
verto_del(r->timer);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
r->timer = verto_add_timeout(vctx, VERTO_EV_FLAG_NONE, on_timeout,
|
|
Packit |
fd8b60 |
r->timeout);
|
|
Packit |
fd8b60 |
if (r->timer != NULL)
|
|
Packit |
fd8b60 |
verto_set_private(r->timer, r, NULL);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return (r->timer == NULL) ? ENOMEM : 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Disconnect from the remote host. */
|
|
Packit |
fd8b60 |
static void
|
|
Packit |
fd8b60 |
remote_disconnect(krad_remote *rr)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
if (rr->fd >= 0)
|
|
Packit |
fd8b60 |
close(rr->fd);
|
|
Packit |
fd8b60 |
verto_del(rr->io);
|
|
Packit |
fd8b60 |
rr->fd = -1;
|
|
Packit |
fd8b60 |
rr->io = NULL;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Add the specified flags to the remote. This automatically manages the
|
|
Packit |
fd8b60 |
* lifecyle of the underlying event. Also connects if disconnected. */
|
|
Packit |
fd8b60 |
static krb5_error_code
|
|
Packit |
fd8b60 |
remote_add_flags(krad_remote *remote, verto_ev_flag flags)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
verto_ev_flag curflags = VERTO_EV_FLAG_NONE;
|
|
Packit |
fd8b60 |
int i;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
flags &= (FLAGS_READ | FLAGS_WRITE);
|
|
Packit |
fd8b60 |
if (remote == NULL || flags == FLAGS_NONE)
|
|
Packit |
fd8b60 |
return EINVAL;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* If there is no connection, connect. */
|
|
Packit |
fd8b60 |
if (remote->fd < 0) {
|
|
Packit |
fd8b60 |
verto_del(remote->io);
|
|
Packit |
fd8b60 |
remote->io = NULL;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
remote->fd = socket(remote->info->ai_family, remote->info->ai_socktype,
|
|
Packit |
fd8b60 |
remote->info->ai_protocol);
|
|
Packit |
fd8b60 |
if (remote->fd < 0)
|
|
Packit |
fd8b60 |
return errno;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
i = connect(remote->fd, remote->info->ai_addr,
|
|
Packit |
fd8b60 |
remote->info->ai_addrlen);
|
|
Packit |
fd8b60 |
if (i < 0) {
|
|
Packit |
fd8b60 |
i = errno;
|
|
Packit |
fd8b60 |
remote_disconnect(remote);
|
|
Packit |
fd8b60 |
return i;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (remote->io == NULL) {
|
|
Packit |
fd8b60 |
remote->io = verto_add_io(remote->vctx, FLAGS_BASE | flags,
|
|
Packit |
fd8b60 |
on_io, remote->fd);
|
|
Packit |
fd8b60 |
if (remote->io == NULL)
|
|
Packit |
fd8b60 |
return ENOMEM;
|
|
Packit |
fd8b60 |
verto_set_private(remote->io, remote, NULL);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
curflags = verto_get_flags(remote->io);
|
|
Packit |
fd8b60 |
if ((curflags & flags) != flags)
|
|
Packit |
fd8b60 |
verto_set_flags(remote->io, FLAGS_BASE | curflags | flags);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Remove the specified flags to the remote. This automatically manages the
|
|
Packit |
fd8b60 |
* lifecyle of the underlying event. */
|
|
Packit |
fd8b60 |
static void
|
|
Packit |
fd8b60 |
remote_del_flags(krad_remote *remote, verto_ev_flag flags)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
if (remote == NULL || remote->io == NULL)
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
flags = verto_get_flags(remote->io) & (FLAGS_READ | FLAGS_WRITE) & ~flags;
|
|
Packit |
fd8b60 |
if (flags == FLAGS_NONE) {
|
|
Packit |
fd8b60 |
verto_del(remote->io);
|
|
Packit |
fd8b60 |
remote->io = NULL;
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
verto_set_flags(remote->io, FLAGS_BASE | flags);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Close the connection and start the timers of all outstanding requests. */
|
|
Packit |
fd8b60 |
static void
|
|
Packit |
fd8b60 |
remote_shutdown(krad_remote *rr)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code retval;
|
|
Packit |
fd8b60 |
request *r;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
remote_disconnect(rr);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Start timers for all unsent packets. */
|
|
Packit |
fd8b60 |
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
|
Packit |
fd8b60 |
if (r->timer == NULL) {
|
|
Packit |
fd8b60 |
retval = request_start_timer(r, rr->vctx);
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
request_finish(r, retval, NULL);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Handle when packets receive no response within their alloted time. */
|
|
Packit |
fd8b60 |
static void
|
|
Packit |
fd8b60 |
on_timeout(verto_ctx *ctx, verto_ev *ev)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
request *req = verto_get_private(ev);
|
|
Packit |
fd8b60 |
krb5_error_code retval = ETIMEDOUT;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
req->timer = NULL; /* Void the timer event. */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* If we have more retries to perform, resend the packet. */
|
|
Packit |
fd8b60 |
if (req->retries-- > 0) {
|
|
Packit |
fd8b60 |
req->sent = 0;
|
|
Packit |
fd8b60 |
retval = remote_add_flags(req->rr, FLAGS_WRITE);
|
|
Packit |
fd8b60 |
if (retval == 0)
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
request_finish(req, retval, NULL);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Write data to the socket. */
|
|
Packit |
fd8b60 |
static void
|
|
Packit |
fd8b60 |
on_io_write(krad_remote *rr)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
const krb5_data *tmp;
|
|
Packit |
fd8b60 |
ssize_t written;
|
|
Packit |
fd8b60 |
request *r;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
|
rpm-build |
10ee26 |
tmp = &r->request->pkt;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* If the packet has already been sent, do nothing. */
|
|
Packit |
fd8b60 |
if (r->sent == tmp->length)
|
|
Packit |
fd8b60 |
continue;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Send the packet. */
|
|
Packit |
fd8b60 |
written = sendto(verto_get_fd(rr->io), tmp->data + r->sent,
|
|
Packit |
fd8b60 |
tmp->length - r->sent, 0, NULL, 0);
|
|
Packit |
fd8b60 |
if (written < 0) {
|
|
Packit |
fd8b60 |
/* Should we try again? */
|
|
Packit |
fd8b60 |
if (errno == EWOULDBLOCK || errno == EAGAIN || errno == ENOBUFS ||
|
|
Packit |
fd8b60 |
errno == EINTR)
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* This error can't be worked around. */
|
|
Packit |
fd8b60 |
remote_shutdown(rr);
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* If the packet was completely sent, set a timeout. */
|
|
Packit |
fd8b60 |
r->sent += written;
|
|
Packit |
fd8b60 |
if (r->sent == tmp->length) {
|
|
Packit |
fd8b60 |
if (request_start_timer(r, rr->vctx) != 0) {
|
|
Packit |
fd8b60 |
request_finish(r, ENOMEM, NULL);
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (remote_add_flags(rr, FLAGS_READ) != 0) {
|
|
Packit |
fd8b60 |
remote_shutdown(rr);
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
remote_del_flags(rr, FLAGS_WRITE);
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Read data from the socket. */
|
|
Packit |
fd8b60 |
static void
|
|
Packit |
fd8b60 |
on_io_read(krad_remote *rr)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
const krad_packet *req = NULL;
|
|
Packit |
fd8b60 |
krad_packet *rsp = NULL;
|
|
Packit |
fd8b60 |
krb5_error_code retval;
|
|
Packit |
fd8b60 |
ssize_t pktlen;
|
|
Packit |
fd8b60 |
request *tmp, *r;
|
|
Packit |
fd8b60 |
int i;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
pktlen = sizeof(rr->buffer_) - rr->buffer.length;
|
|
Packit |
fd8b60 |
if (rr->info->ai_socktype == SOCK_STREAM) {
|
|
Packit |
fd8b60 |
pktlen = krad_packet_bytes_needed(&rr->buffer);
|
|
Packit |
fd8b60 |
if (pktlen < 0) {
|
|
Packit |
fd8b60 |
/* If we received a malformed packet on a stream socket,
|
|
Packit |
fd8b60 |
* assume the socket to be unrecoverable. */
|
|
Packit |
fd8b60 |
remote_shutdown(rr);
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Read the packet. */
|
|
Packit |
fd8b60 |
i = recv(verto_get_fd(rr->io), rr->buffer.data + rr->buffer.length,
|
|
Packit |
fd8b60 |
pktlen, 0);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* On these errors, try again. */
|
|
Packit |
fd8b60 |
if (i < 0 && (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR))
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* On any other errors or on EOF, the socket is unrecoverable. */
|
|
Packit |
fd8b60 |
if (i <= 0) {
|
|
Packit |
fd8b60 |
remote_shutdown(rr);
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* If we have a partial read or just the header, try again. */
|
|
Packit |
fd8b60 |
rr->buffer.length += i;
|
|
Packit |
fd8b60 |
pktlen = krad_packet_bytes_needed(&rr->buffer);
|
|
Packit |
fd8b60 |
if (rr->info->ai_socktype == SOCK_STREAM && pktlen > 0)
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Decode the packet. */
|
|
Packit |
fd8b60 |
tmp = K5_TAILQ_FIRST(&rr->list);
|
|
Packit |
fd8b60 |
retval = krad_packet_decode_response(rr->kctx, rr->secret, &rr->buffer,
|
|
Packit |
fd8b60 |
(krad_packet_iter_cb)iterator, &tmp,
|
|
Packit |
fd8b60 |
&req, &rsp;;
|
|
Packit |
fd8b60 |
rr->buffer.length = 0;
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Match the response with an outstanding request. */
|
|
Packit |
fd8b60 |
if (req != NULL) {
|
|
Packit |
fd8b60 |
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
|
Packit |
fd8b60 |
if (r->request == req &&
|
|
rpm-build |
10ee26 |
r->sent == req->pkt.length) {
|
|
Packit |
fd8b60 |
request_finish(r, 0, rsp);
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krad_packet_free(rsp);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Handle when IO is ready on the socket. */
|
|
Packit |
fd8b60 |
static void
|
|
Packit |
fd8b60 |
on_io(verto_ctx *ctx, verto_ev *ev)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krad_remote *rr;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
rr = verto_get_private(ev);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (verto_get_fd_state(ev) & VERTO_EV_FLAG_IO_WRITE)
|
|
Packit |
fd8b60 |
on_io_write(rr);
|
|
Packit |
fd8b60 |
else
|
|
Packit |
fd8b60 |
on_io_read(rr);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_error_code
|
|
Packit |
fd8b60 |
kr_remote_new(krb5_context kctx, verto_ctx *vctx, const struct addrinfo *info,
|
|
Packit |
fd8b60 |
const char *secret, krad_remote **rr)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code retval = ENOMEM;
|
|
Packit |
fd8b60 |
krad_remote *tmp = NULL;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
tmp = calloc(1, sizeof(krad_remote));
|
|
Packit |
fd8b60 |
if (tmp == NULL)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
tmp->kctx = kctx;
|
|
Packit |
fd8b60 |
tmp->vctx = vctx;
|
|
Packit |
fd8b60 |
tmp->buffer = make_data(tmp->buffer_, 0);
|
|
Packit |
fd8b60 |
K5_TAILQ_INIT(&tmp->list);
|
|
Packit |
fd8b60 |
tmp->fd = -1;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
tmp->secret = strdup(secret);
|
|
Packit |
fd8b60 |
if (tmp->secret == NULL)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
tmp->info = k5memdup(info, sizeof(*info), &retval);
|
|
Packit |
fd8b60 |
if (tmp->info == NULL)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
tmp->info->ai_addr = k5memdup(info->ai_addr, info->ai_addrlen, &retval);
|
|
Packit |
fd8b60 |
if (tmp->info == NULL)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
tmp->info->ai_next = NULL;
|
|
Packit |
fd8b60 |
tmp->info->ai_canonname = NULL;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*rr = tmp;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
error:
|
|
Packit |
fd8b60 |
kr_remote_free(tmp);
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
void
|
|
Packit |
fd8b60 |
kr_remote_free(krad_remote *rr)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
if (rr == NULL)
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
while (!K5_TAILQ_EMPTY(&rr->list))
|
|
Packit |
fd8b60 |
request_finish(K5_TAILQ_FIRST(&rr->list), ECANCELED, NULL);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
free(rr->secret);
|
|
Packit |
fd8b60 |
if (rr->info != NULL)
|
|
Packit |
fd8b60 |
free(rr->info->ai_addr);
|
|
Packit |
fd8b60 |
free(rr->info);
|
|
Packit |
fd8b60 |
remote_disconnect(rr);
|
|
Packit |
fd8b60 |
free(rr);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_error_code
|
|
Packit |
fd8b60 |
kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs,
|
|
Packit |
fd8b60 |
krad_cb cb, void *data, int timeout, size_t retries,
|
|
Packit |
fd8b60 |
const krad_packet **pkt)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krad_packet *tmp = NULL;
|
|
Packit |
fd8b60 |
krb5_error_code retval;
|
|
Packit |
fd8b60 |
request *r;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (rr->info->ai_socktype == SOCK_STREAM)
|
|
Packit |
fd8b60 |
retries = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
r = K5_TAILQ_FIRST(&rr->list);
|
|
Packit |
fd8b60 |
retval = krad_packet_new_request(rr->kctx, rr->secret, code, attrs,
|
|
Packit |
fd8b60 |
(krad_packet_iter_cb)iterator, &r, &tmp);
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
goto error;
|
|
rpm-build |
10ee26 |
else if (tmp->is_fips && rr->info->ai_family != AF_LOCAL &&
|
|
rpm-build |
10ee26 |
rr->info->ai_family != AF_UNIX) {
|
|
rpm-build |
10ee26 |
/* This would expose cleartext passwords, so abort. */
|
|
rpm-build |
10ee26 |
retval = ESOCKTNOSUPPORT;
|
|
rpm-build |
10ee26 |
goto error;
|
|
rpm-build |
10ee26 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
|
Packit |
fd8b60 |
if (r->request == tmp) {
|
|
Packit |
fd8b60 |
retval = EALREADY;
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
timeout = timeout / (retries + 1);
|
|
Packit |
fd8b60 |
retval = request_new(rr, tmp, timeout, retries, cb, data, &r);
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = remote_add_flags(rr, FLAGS_WRITE);
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
K5_TAILQ_INSERT_TAIL(&rr->list, r, list);
|
|
Packit |
fd8b60 |
if (pkt != NULL)
|
|
Packit |
fd8b60 |
*pkt = tmp;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
error:
|
|
Packit |
fd8b60 |
krad_packet_free(tmp);
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
void
|
|
Packit |
fd8b60 |
kr_remote_cancel(krad_remote *rr, const krad_packet *pkt)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
request *r;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
|
Packit |
fd8b60 |
if (r->request == pkt) {
|
|
Packit |
fd8b60 |
request_finish(r, ECANCELED, NULL);
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_boolean
|
|
Packit |
fd8b60 |
kr_remote_equals(const krad_remote *rr, const struct addrinfo *info,
|
|
Packit |
fd8b60 |
const char *secret)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
struct sockaddr_un *a, *b;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (strcmp(rr->secret, secret) != 0)
|
|
Packit |
fd8b60 |
return FALSE;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (info->ai_addrlen != rr->info->ai_addrlen)
|
|
Packit |
fd8b60 |
return FALSE;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (info->ai_family != rr->info->ai_family)
|
|
Packit |
fd8b60 |
return FALSE;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (info->ai_socktype != rr->info->ai_socktype)
|
|
Packit |
fd8b60 |
return FALSE;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (info->ai_protocol != rr->info->ai_protocol)
|
|
Packit |
fd8b60 |
return FALSE;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (info->ai_flags != rr->info->ai_flags)
|
|
Packit |
fd8b60 |
return FALSE;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (memcmp(rr->info->ai_addr, info->ai_addr, info->ai_addrlen) != 0) {
|
|
Packit |
fd8b60 |
/* AF_UNIX fails the memcmp() test due to uninitialized bytes after the
|
|
Packit |
fd8b60 |
* socket name. */
|
|
Packit |
fd8b60 |
if (info->ai_family != AF_UNIX)
|
|
Packit |
fd8b60 |
return FALSE;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
a = (struct sockaddr_un *)info->ai_addr;
|
|
Packit |
fd8b60 |
b = (struct sockaddr_un *)rr->info->ai_addr;
|
|
Packit |
fd8b60 |
if (strncmp(a->sun_path, b->sun_path, sizeof(a->sun_path)) != 0)
|
|
Packit |
fd8b60 |
return FALSE;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return TRUE;
|
|
Packit |
fd8b60 |
}
|