*/
/*
- * $Id: krb5-security.c,v 1.12 2006/02/21 04:13:55 ktill Exp $
+ * $Id: krb5-security.c,v 1.22 2006/06/16 10:55:05 martinea Exp $
*
* krb5-security.c - kerberos V5 security module
*/
#include "config.h"
#ifdef KRB5_SECURITY
#include "amanda.h"
+#include "util.h"
#include "arglist.h"
#include "event.h"
#include "packet.h"
#include "queue.h"
#include "security.h"
+#include "security-util.h"
#include "stream.h"
#include "version.h"
struct krb5_stream *ks; /* virtual stream we xmit over */
union {
- void (*recvpkt) P((void *, pkt_t *, security_status_t));
+ void (*recvpkt)(void *, pkt_t *, security_status_t);
/* func to call when packet recvd */
- void (*connect) P((void *, security_handle_t *, security_status_t));
+ void (*connect)(void *, security_handle_t *, security_status_t);
/* func to call when connected */
} fn;
void *arg; /* argument to pass function */
+ void *datap; /* argument to pass function */
event_handle_t *ev_wait; /* wait handle for connects */
- char *(*conf_fn) P((char *, void *)); /* used to get config info */
+ char *(*conf_fn)(char *, void *); /* used to get config info */
event_handle_t *ev_timeout; /* timeout handle for recv */
};
struct krb5_conn *kc; /* physical connection */
int handle; /* protocol handle */
event_handle_t *ev_read; /* read (EV_WAIT) event handle */
- void (*fn) P((void *, void *, int)); /* read event fn */
+ void (*fn)(void *, void *, ssize_t);/* read event fn */
void *arg; /* arg for previous */
+ char buf[KRB5_STREAM_BUFSIZE];
+ ssize_t len;
};
/*
* Interface functions
*/
-static int krb5_sendpkt P((void *, pkt_t *));
-static int krb5_stream_accept P((void *));
-static int krb5_stream_auth P((void *));
-static int krb5_stream_id P((void *));
-static int krb5_stream_write P((void *, const void *, size_t));
-static void *krb5_stream_client P((void *, int));
-static void *krb5_stream_server P((void *));
-static void krb5_accept P((int, int,
- void (*)(security_handle_t *, pkt_t *)));
-static void krb5_close P((void *));
-static void krb5_connect P((const char *,
- char *(*)(char *, void *),
- void (*)(void *, security_handle_t *, security_status_t), void *));
-static void krb5_recvpkt P((void *,
- void (*)(void *, pkt_t *, security_status_t), void *, int));
-static void krb5_recvpkt_cancel P((void *));
-static void krb5_stream_close P((void *));
-static void krb5_stream_read P((void *, void (*)(void *, void *, int),
- void *));
-static void krb5_stream_read_cancel P((void *));
+static ssize_t krb5_sendpkt(void *, pkt_t *);
+static int krb5_stream_accept(void *);
+static int krb5_stream_auth(void *);
+static int krb5_stream_id(void *);
+static int krb5_stream_write(void *, const void *, size_t);
+static void * krb5_stream_client(void *, int);
+static void * krb5_stream_server(void *);
+static void krb5_accept(const struct security_driver *, int, int,
+ void (*)(security_handle_t *, pkt_t *));
+static void krb5_close(void *);
+static void krb5_connect(const char *, char *(*)(char *, void *),
+ void (*)(void *, security_handle_t *, security_status_t),
+ void *, void *);
+static void krb5_recvpkt(void *, void (*)(void *, pkt_t *, security_status_t),
+ void *, int);
+static void krb5_recvpkt_cancel(void *);
+static void krb5_stream_close(void *);
+static void krb5_stream_read(void *, void (*)(void *, void *, ssize_t), void *);
+static ssize_t krb5_stream_read_sync(void *, void **);
+static void krb5_stream_read_cancel(void *);
/*
* This is our interface to the outside world.
krb5_stream_id,
krb5_stream_write,
krb5_stream_read,
+ krb5_stream_read_sync,
krb5_stream_read_cancel,
+ sec_close_connection_none,
};
/*
static struct {
TAILQ_HEAD(, krb5_conn) tailq;
int qlength;
-} connq = {
- TAILQ_HEAD_INITIALIZER(connq.tailq), 0
+} krb5_connq = {
+ TAILQ_HEAD_INITIALIZER(krb5_connq.tailq), 0
};
-#define connq_first() TAILQ_FIRST(&connq.tailq)
-#define connq_next(kc) TAILQ_NEXT(kc, tq)
-#define connq_append(kc) do { \
- TAILQ_INSERT_TAIL(&connq.tailq, kc, tq); \
- connq.qlength++; \
+#define krb5_connq_first() TAILQ_FIRST(&krb5_connq.tailq)
+#define krb5_connq_next(kc) TAILQ_NEXT(kc, tq)
+#define krb5_connq_append(kc) do { \
+ TAILQ_INSERT_TAIL(&krb5_connq.tailq, kc, tq); \
+ krb5_connq.qlength++; \
} while (0)
-#define connq_remove(kc) do { \
- assert(connq.qlength > 0); \
- TAILQ_REMOVE(&connq.tailq, kc, tq); \
- connq.qlength--; \
+#define krb5_connq_remove(kc) do { \
+ assert(krb5_connq.qlength > 0); \
+ TAILQ_REMOVE(&krb5_connq.tailq, kc, tq); \
+ krb5_connq.qlength--; \
} while (0)
static int newhandle = 1;
* created. If NULL, no new handles are created.
* It is passed the new handle and the received pkt
*/
-static void (*accept_fn) P((security_handle_t *, pkt_t *));
+static void (*accept_fn)(security_handle_t *, pkt_t *);
/*
* Local functions
*/
-static void init P((void));
+static void init(void);
#ifdef BROKEN_MEMORY_CCACHE
-static void cleanup P((void));
+static void cleanup(void);
#endif
-static const char *get_tgt P((char *, char *));
-static void open_callback P((void *));
-static void connect_callback P((void *));
-static void connect_timeout P((void *));
-static int send_token P((struct krb5_conn *, int, const gss_buffer_desc *));
-static int recv_token P((struct krb5_conn *, int *, gss_buffer_desc *, int));
-static void recvpkt_callback P((void *, void *, ssize_t));
-static void recvpkt_timeout P((void *));
-static void stream_read_callback P((void *));
-static int gss_server P((struct krb5_conn *));
-static int gss_client P((struct krb5_handle *));
-static const char *gss_error P((OM_uint32, OM_uint32));
+static const char *get_tgt(char *, char *);
+static void open_callback(void *);
+static void connect_callback(void *);
+static void connect_timeout(void *);
+static int send_token(struct krb5_conn *, int, const gss_buffer_desc *);
+static ssize_t recv_token(struct krb5_conn *, int *, gss_buffer_desc *, int);
+static void recvpkt_callback(void *, void *, ssize_t);
+static void recvpkt_timeout(void *);
+static void stream_read_callback(void *);
+static void stream_read_sync_callback2(void *, void *, ssize_t);
+static int gss_server(struct krb5_conn *);
+static int gss_client(struct krb5_handle *);
+static const char *gss_error(OM_uint32, OM_uint32);
#ifdef AMANDA_KRB5_ENCRYPT
-static int kdecrypt P((struct krb5_stream *, gss_buffer_desc *,
- gss_buffer_desc *));
-static int kencrypt P((struct krb5_stream *, gss_buffer_desc *,
- gss_buffer_desc *));
+static int kdecrypt(struct krb5_stream *, gss_buffer_desc *, gss_buffer_desc *);
+static int kencrypt(struct krb5_stream *, gss_buffer_desc *, gss_buffer_desc *);
#endif
-static struct krb5_conn *conn_get P((const char *));
-static void conn_put P((struct krb5_conn *));
-static void conn_read P((struct krb5_conn *));
-static void conn_read_cancel P((struct krb5_conn *));
-static void conn_read_callback P((void *));
-static int conn_run_frameq P((struct krb5_conn *, struct krb5_stream *));
-static int net_writev P((int, struct iovec *, int));
-static ssize_t net_read P((struct krb5_conn *, void *, size_t, int));
-static int net_read_fillbuf P((struct krb5_conn *, int));
-static char *krb5_checkuser(char *, char *, char *);
-static void parse_pkt P((pkt_t *, const void *, size_t));
+static struct krb5_conn *conn_get(const char *);
+static void conn_put(struct krb5_conn *);
+static void conn_read(struct krb5_conn *);
+static void conn_read_cancel(struct krb5_conn *);
+static void conn_read_callback(void *);
+static int conn_run_frameq(struct krb5_conn *, struct krb5_stream *);
+static char * krb5_checkuser(char *, char *, char *);
/*
* up a network "connection".
*/
static void
-krb5_connect(hostname, conf_fn, fn, arg)
- const char *hostname;
- char *(*conf_fn) P((char *, void *));
- void (*fn) P((void *, security_handle_t *, security_status_t));
- void *arg;
+krb5_connect(
+ const char *hostname,
+ char * (*conf_fn)(char *, void *),
+ void (*fn)(void *, security_handle_t *, security_status_t),
+ void * arg,
+ void * datap)
{
struct krb5_handle *kh;
struct hostent *he;
struct servent *se;
- int port, fd;
+ int fd;
+ int port;
const char *err;
char *keytab_name = NULL;
char *principal_name = NULL;
*/
init();
- kh = alloc(sizeof(*kh));
+ kh = alloc(SIZEOF(*kh));
security_handleinit(&kh->sech, &krb5_security_driver);
kh->hostname = NULL;
kh->ks = NULL;
keytab_name = AMANDA_KEYTAB;
#else
if(conf_fn) {
- keytab_name = conf_fn("krb5keytab", arg);
+ keytab_name = conf_fn("krb5keytab", datap);
}
#endif
#ifdef AMANDA_PRINCIPAL
principal_name = AMANDA_PRINCIPAL;
#else
if(conf_fn) {
- principal_name = conf_fn("krb5principal", arg);
+ principal_name = conf_fn("krb5principal", datap);
}
#endif
kh->fn.connect = fn;
kh->conf_fn = conf_fn;
kh->arg = arg;
+ kh->datap = datap;
kh->hostname = stralloc(he->h_name);
kh->ks = krb5_stream_client(kh, newhandle++);
* We need to open a new connection. See if we have too
* many connections open.
*/
- if (connq.qlength > AMANDA_KRB5_MAXCONN) {
+ if (krb5_connq.qlength > AMANDA_KRB5_MAXCONN) {
k5printf(("krb5_connect: too many conections (%d), delaying %s\n",
- connq.qlength, kh->hostname));
+ krb5_connq.qlength, kh->hostname));
krb5_stream_close(kh->ks);
kh->ev_wait = event_register((event_id_t)open_callback,
EV_WAIT, open_callback, kh);
* so we will know when the socket comes alive.
* We also register a timeout.
*/
- kh->ev_wait = event_register(fd, EV_WRITEFD, connect_callback, kh);
- kh->ev_timeout = event_register(GSS_TIMEOUT, EV_TIME, connect_timeout, kh);
+ kh->ev_wait = event_register((event_id_t)fd, EV_WRITEFD,
+ connect_callback, kh);
+ kh->ev_timeout = event_register((event_id_t)GSS_TIMEOUT, EV_TIME,
+ connect_timeout, kh);
return;
* we can open more.
*/
static void
-open_callback(cookie)
- void *cookie;
+open_callback(
+ void * cookie)
{
struct krb5_handle *kh = cookie;
k5printf(("krb5: open_callback: possible connections available, retry %s\n",
kh->hostname));
- krb5_connect(kh->hostname, kh->conf_fn, kh->fn.connect, kh->arg);
+ krb5_connect(kh->hostname, kh->conf_fn, kh->fn.connect, kh->arg,kh->datap);
amfree(kh->hostname);
amfree(kh);
}
* to be authenticated.
*/
static void
-connect_callback(cookie)
- void *cookie;
+connect_callback(
+ void * cookie)
{
struct krb5_handle *kh = cookie;
* Called if a connection times out before completion.
*/
static void
-connect_timeout(cookie)
- void *cookie;
+connect_timeout(
+ void * cookie)
{
struct krb5_handle *kh = cookie;
* Setup to handle new incoming connections
*/
static void
-krb5_accept(in, out, fn)
- int in, out;
- void (*fn) P((security_handle_t *, pkt_t *));
+krb5_accept(
+ const struct security_driver *driver,
+ int in,
+ int out,
+ void (*fn)(security_handle_t *, pkt_t *))
{
struct sockaddr_in sin;
- size_t len;
+ socklen_t len;
struct krb5_conn *kc;
struct hostent *he;
*/
init();
- len = sizeof(sin);
+ /* shut up compiler */
+ driver=driver;
+ out=out;
+
+ len = SIZEOF(sin);
if (getpeername(in, (struct sockaddr *)&sin, &len) < 0)
return;
- he = gethostbyaddr((void *)&sin.sin_addr, sizeof(sin.sin_addr), AF_INET);
+ he = gethostbyaddr((void *)&sin.sin_addr, SIZEOF(sin.sin_addr), AF_INET);
if (he == NULL)
return;
* for the lack of a connection (kc->fd == -1) and set one up.
*/
static struct krb5_conn *
-conn_get(hostname)
- const char *hostname;
+conn_get(
+ const char * hostname)
{
struct krb5_conn *kc;
k5printf(("krb5: conn_get: %s\n", hostname));
- for (kc = connq_first(); kc != NULL; kc = connq_next(kc)) {
+ for (kc = krb5_connq_first(); kc != NULL; kc = krb5_connq_next(kc)) {
if (strcasecmp(hostname, kc->hostname) == 0)
break;
}
* We can't be creating a new handle if we are the client
*/
assert(accept_fn == NULL);
- kc = alloc(sizeof(*kc));
+ kc = alloc(SIZEOF(*kc));
kc->fd = -1;
kc->readbuf.left = 0;
kc->readbuf.size = 0;
kc->state = unauthed;
kc->ev_read = NULL;
- strncpy(kc->hostname, hostname, sizeof(kc->hostname) - 1);
- kc->hostname[sizeof(kc->hostname) - 1] = '\0';
+ strncpy(kc->hostname, hostname, SIZEOF(kc->hostname) - 1);
+ kc->hostname[SIZEOF(kc->hostname) - 1] = '\0';
kc->errmsg = NULL;
kc->gss_context = GSS_C_NO_CONTEXT;
/*
*/
kc->refcnt = 2;
TAILQ_INIT(&kc->frameq);
- connq_append(kc);
+ krb5_connq_append(kc);
return (kc);
}
* reference.
*/
static void
-conn_put(kc)
- struct krb5_conn *kc;
+conn_put(
+ struct krb5_conn * kc)
{
OM_uint32 min_stat;
struct krb5_frame *kf;
amfree(kf->tok.value);
amfree(kf);
}
- connq_remove(kc);
+ krb5_connq_remove(kc);
amfree(kc);
/* signal that a connection is available */
event_wakeup((event_id_t)open_callback);
* already receiving read events.
*/
static void
-conn_read(kc)
- struct krb5_conn *kc;
+conn_read(
+ struct krb5_conn *kc)
{
if (kc->ev_read != NULL) {
}
k5printf(("krb5: conn_read registering event handler for %s\n",
kc->hostname));
- kc->ev_read = event_register(kc->fd, EV_READFD, conn_read_callback, kc);
+ kc->ev_read = event_register((event_id_t)kc->fd, EV_READFD, conn_read_callback, kc);
kc->ev_read_refcnt = 1;
}
static void
-conn_read_cancel(kc)
- struct krb5_conn *kc;
+conn_read_cancel(
+ struct krb5_conn * kc)
{
if (--kc->ev_read_refcnt > 0) {
* frees a handle allocated by the above
*/
static void
-krb5_close(inst)
- void *inst;
+krb5_close(
+ void * inst)
{
struct krb5_handle *kh = inst;
/*
* Transmit a packet. Encrypt first.
*/
-static int
-krb5_sendpkt(cookie, pkt)
- void *cookie;
- pkt_t *pkt;
+static ssize_t
+krb5_sendpkt(
+ void * cookie,
+ pkt_t * pkt)
{
struct krb5_handle *kh = cookie;
gss_buffer_desc tok;
int rval;
- unsigned char c, *buf;
+ unsigned char *buf;
assert(kh != NULL);
assert(pkt != NULL);
k5printf(("krb5: sendpkt: enter\n"));
if (pkt->body[0] == '\0') {
- c = (unsigned char)pkt->type;
tok.length = 1;
- tok.value = &c;
+ tok.value = alloc(SIZEOF(pkt->type));
+ memcpy(tok.value, &pkt->type, sizeof(unsigned char));
} else {
tok.length = strlen(pkt->body) + 2;
tok.value = alloc(tok.length);
buf = tok.value;
*buf++ = (unsigned char)pkt->type;
- strncpy(buf, pkt->body, tok.length - 2);
+ strncpy((char *)buf, pkt->body, tok.length - 2);
buf[tok.length - 2] = '\0';
}
rval = krb5_stream_write(kh->ks, tok.value, tok.length);
if (rval < 0)
security_seterror(&kh->sech, security_stream_geterror(&kh->ks->secstr));
- if (tok.length > 1)
- amfree(tok.value);
+ /*@ignore@*/
+ amfree(tok.value);
+ /*@end@*/
return (rval);
}
* it has been read.
*/
static void
-krb5_recvpkt(cookie, fn, arg, timeout)
- void *cookie, *arg;
- void (*fn) P((void *, pkt_t *, security_status_t));
- int timeout;
+krb5_recvpkt(
+ void * cookie,
+ void (*fn)(void *, pkt_t *, security_status_t),
+ void * arg,
+ int timeout)
{
struct krb5_handle *kh = cookie;
if (timeout < 0)
kh->ev_timeout = NULL;
else
- kh->ev_timeout = event_register(timeout, EV_TIME, recvpkt_timeout, kh);
+ kh->ev_timeout = event_register((event_id_t)timeout, EV_TIME,
+ recvpkt_timeout, kh);
kh->fn.recvpkt = fn;
kh->arg = arg;
* Remove a async receive request from the queue
*/
static void
-krb5_recvpkt_cancel(cookie)
- void *cookie;
+krb5_recvpkt_cancel(
+ void * cookie)
{
struct krb5_handle *kh = cookie;
* net is for it.
*/
static void
-recvpkt_callback(cookie, buf, bufsize)
- void *cookie, *buf;
- ssize_t bufsize;
+recvpkt_callback(
+ void *cookie,
+ void *buf,
+ ssize_t bufsize)
{
pkt_t pkt;
struct krb5_handle *kh = cookie;
(*kh->fn.recvpkt)(kh->arg, NULL, S_ERROR);
return;
default:
- parse_pkt(&pkt, buf, bufsize);
+ parse_pkt(&pkt, buf, (size_t)bufsize);
k5printf(("krb5: received %s pkt (%d) from %s, contains:\n\n\"%s\"\n\n",
pkt_type2str(pkt.type), pkt.type, kh->hostname, pkt.body));
(*kh->fn.recvpkt)(kh->arg, &pkt, S_OK);
* This is called when a handle times out before receiving a packet.
*/
static void
-recvpkt_timeout(cookie)
- void *cookie;
+recvpkt_timeout(
+ void * cookie)
{
struct krb5_handle *kh = cookie;
* object and allocate a new handle for it.
*/
static void *
-krb5_stream_server(h)
- void *h;
+krb5_stream_server(
+ void * h)
{
struct krb5_handle *kh = h;
struct krb5_stream *ks;
assert(kh != NULL);
- ks = alloc(sizeof(*ks));
+ ks = alloc(SIZEOF(*ks));
security_streaminit(&ks->secstr, &krb5_security_driver);
ks->kc = conn_get(kh->hostname);
/*
* so as not to conflict with the amanda server's handle numbers,
* we start at 5000 and work down
*/
- ks->handle = 5000 - newhandle++;
+ ks->handle = (int)(5000 - newhandle++);
ks->ev_read = NULL;
k5printf(("krb5: stream_server: created stream %d\n", ks->handle));
return (ks);
* Nothing needed for krb5.
*/
static int
-krb5_stream_accept(s)
- void *s;
+krb5_stream_accept(
+ void * s)
{
+ /* shut up compiler */
+ s = s;
+
return (0);
}
* with the supplied handle.
*/
static void *
-krb5_stream_client(h, id)
- void *h;
- int id;
+krb5_stream_client(
+ void * h,
+ int id)
{
struct krb5_handle *kh = h;
struct krb5_stream *ks;
return (NULL);
}
- ks = alloc(sizeof(*ks));
+ ks = alloc(SIZEOF(*ks));
security_streaminit(&ks->secstr, &krb5_security_driver);
- ks->handle = id;
+ ks->handle = (int)id;
ks->ev_read = NULL;
ks->kc = conn_get(kh->hostname);
* Close and unallocate resources for a stream.
*/
static void
-krb5_stream_close(s)
- void *s;
+krb5_stream_close(
+ void * s)
{
struct krb5_stream *ks = s;
* on startup.
*/
static int
-krb5_stream_auth(s)
- void *s;
+krb5_stream_auth(
+ void * s)
{
+ /* shut up compiler */
+ s = s;
return (0);
}
* port.
*/
static int
-krb5_stream_id(s)
- void *s;
+krb5_stream_id(
+ void * s)
{
struct krb5_stream *ks = s;
* Write a chunk of data to a stream. Blocks until completion.
*/
static int
-krb5_stream_write(s, buf, size)
- void *s;
- const void *buf;
- size_t size;
+krb5_stream_write(
+ void * s,
+ const void *buf,
+ size_t size)
{
struct krb5_stream *ks = s;
gss_buffer_desc tok;
* function and arg when completed.
*/
static void
-krb5_stream_read(s, fn, arg)
- void *s, *arg;
- void (*fn) P((void *, void *, int));
+krb5_stream_read(
+ void * s,
+ void (*fn)(void *, void *, ssize_t),
+ void * arg)
{
struct krb5_stream *ks = s;
}
}
+/*
+ * Submit a request to read some data. Calls back with the given
+ * function and arg when completed.
+ */
+static ssize_t
+krb5_stream_read_sync(
+ void * s,
+ void **buf)
+{
+ struct krb5_stream *ks = s;
+
+ assert(ks != NULL);
+
+ /*
+ * Only one read request can be active per stream.
+ */
+ ks->fn = stream_read_sync_callback2;
+ ks->arg = ks;
+
+ /*
+ * First see if there's any queued frames for this stream.
+ * If so, we're done.
+ */
+ if (conn_run_frameq(ks->kc, ks) > 0)
+ return ks->len;
+
+ if (ks->ev_read != NULL)
+ event_release(ks->ev_read);
+
+ ks->ev_read = event_register((event_id_t)ks->kc, EV_WAIT,
+ stream_read_callback, ks);
+ conn_read(ks->kc);
+ event_wait(ks->ev_read);
+ buf = (void **)&ks->buf;
+ return ks->len;
+}
+
+
+/*
+ * Callback for krb5_stream_read_sync
+ */
+static void
+stream_read_sync_callback2(
+ void * arg,
+ void * buf,
+ ssize_t size)
+{
+ struct krb5_stream *ks = arg;
+
+ assert(ks != NULL);
+
+ k5printf(("krb5: stream_read_sync_callback2: handle %d\n", ks->handle));
+
+ memcpy(ks->buf, buf, (size_t)size);
+ ks->len = size;
+}
+
/*
* Cancel a previous stream read request. It's ok if we didn't have a read
* scheduled.
*/
static void
-krb5_stream_read_cancel(s)
- void *s;
+krb5_stream_read_cancel(
+ void * s)
{
struct krb5_stream *ks = s;
* Callback for krb5_stream_read
*/
static void
-stream_read_callback(arg)
- void *arg;
+stream_read_callback(
+ void * arg)
{
struct krb5_stream *ks = arg;
* Returns 1 if a frame was found and processed.
*/
static int
-conn_run_frameq(kc, ks)
- struct krb5_conn *kc;
- struct krb5_stream *ks;
+conn_run_frameq(
+ /*@keep@*/ struct krb5_conn * kc,
+ /*@keep@*/ struct krb5_stream * ks)
{
struct krb5_frame *kf, *nextkf;
gss_buffer_desc *enctok, *dectok;
{
k5printf(("krb5: stream_read_callback: read %d bytes from %s:%d\n",
dectok->length, ks->kc->hostname, ks->handle));
- (*ks->fn)(ks->arg, dectok->value, dectok->length);
+ (*ks->fn)(ks->arg, dectok->value, (ssize_t)dectok->length);
#ifdef AMANDA_KRB5_ENCRYPT
gss_release_buffer(&min_stat, dectok);
#endif
* and does the real callback if so.
*/
static void
-conn_read_callback(cookie)
- void *cookie;
+conn_read_callback(
+ void * cookie)
{
struct krb5_conn *kc = cookie;
struct krb5_handle *kh;
k5printf(("krb5: conn_read_callback\n"));
- kf = alloc(sizeof(*kf));
+ kf = alloc(SIZEOF(*kf));
TAILQ_INSERT_TAIL(&kc->frameq, kf, tq);
/* Read the data off the wire. If we get errors, shut down. */
return;
}
- kh = alloc(sizeof(*kh));
+ kh = alloc(SIZEOF(*kh));
security_handleinit(&kh->sech, &krb5_security_driver);
kh->hostname = stralloc(kc->hostname);
kh->ks = krb5_stream_client(kh, kf->handle);
* Negotiate a krb5 gss context from the client end.
*/
static int
-gss_client(kh)
- struct krb5_handle *kh;
+gss_client(
+ struct krb5_handle *kh)
{
struct krb5_stream *ks = kh->ks;
struct krb5_conn *kc = ks->kc;
send_tok.length = strlen(send_tok.value) + 1;
maj_stat = gss_import_name(&min_stat, &send_tok, GSS_C_NULL_OID,
&gss_name);
- if (maj_stat != GSS_S_COMPLETE) {
+ if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
security_seterror(&kh->sech, "can't import name %s: %s",
(char *)send_tok.value, gss_error(maj_stat, min_stat));
amfree(send_tok.value);
* and only if the server has another token to send us.
*/
+ recv_tok.value = NULL;
for (recv_tok.length = 0;;) {
min_stat = 0;
maj_stat = gss_init_sec_context(&min_stat,
&kc->gss_context,
gss_name,
GSS_C_NULL_OID,
- GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG,
+ (OM_uint32)GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG,
0, NULL, /* no channel bindings */
(recv_tok.length == 0 ? GSS_C_NO_BUFFER : &recv_tok),
NULL, /* ignore mech type */
recv_tok.length = 0;
}
- if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
+ if (maj_stat != (OM_uint32)GSS_S_COMPLETE && maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED) {
security_seterror(&kh->sech,
"error getting gss context: %s",
gss_error(maj_stat, min_stat));
/*
* If we need to continue, then register for more packets
*/
- if (maj_stat != GSS_S_CONTINUE_NEEDED)
+ if (maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED)
break;
if ((rc = recv_token(kc, NULL, &recv_tok, GSS_TIMEOUT)) <= 0) {
* Negotiate a krb5 gss context from the server end.
*/
static int
-gss_server(kc)
- struct krb5_conn *kc;
+gss_server(
+ struct krb5_conn * kc)
{
OM_uint32 maj_stat, min_stat, ret_flags;
gss_buffer_desc send_tok, recv_tok;
*/
euid = geteuid();
if (getuid() != 0) {
- snprintf(errbuf, sizeof(errbuf),
+ snprintf(errbuf, SIZEOF(errbuf),
"real uid is %ld, needs to be 0 to read krb5 host key",
(long)getuid());
goto out;
}
if (seteuid(0) < 0) {
- snprintf(errbuf, sizeof(errbuf),
+ snprintf(errbuf, SIZEOF(errbuf),
"can't seteuid to uid 0: %s", strerror(errno));
goto out;
}
}
maj_stat = gss_import_name(&min_stat, &send_tok, GSS_C_NULL_OID,
&gss_name);
- if (maj_stat != GSS_S_COMPLETE) {
+ if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
seteuid(euid);
- snprintf(errbuf, sizeof(errbuf),
+ snprintf(errbuf, SIZEOF(errbuf),
"can't import name %s: %s", (char *)send_tok.value,
gss_error(maj_stat, min_stat));
amfree(send_tok.value);
maj_stat = gss_acquire_cred(&min_stat, gss_name, 0,
GSS_C_NULL_OID_SET, GSS_C_ACCEPT, &gss_creds, NULL, NULL);
- if (maj_stat != GSS_S_COMPLETE) {
- snprintf(errbuf, sizeof(errbuf),
+ if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
+ snprintf(errbuf, SIZEOF(errbuf),
"can't acquire creds for host key host/%s: %s", hostname,
gss_error(maj_stat, min_stat));
gss_release_name(&min_stat, &gss_name);
for (recv_tok.length = 0;;) {
if ((rc = recv_token(kc, NULL, &recv_tok, GSS_TIMEOUT)) <= 0) {
if (rc < 0) {
- snprintf(errbuf, sizeof(errbuf),
+ snprintf(errbuf, SIZEOF(errbuf),
"recv error in gss loop: %s", kc->errmsg);
amfree(kc->errmsg);
} else
- snprintf(errbuf, sizeof(errbuf), "EOF in gss loop");
+ snprintf(errbuf, SIZEOF(errbuf), "EOF in gss loop");
goto out;
}
gss_creds, &recv_tok, GSS_C_NO_CHANNEL_BINDINGS,
&gss_name, &doid, &send_tok, &ret_flags, NULL, NULL);
- if (maj_stat != GSS_S_COMPLETE &&
- maj_stat != GSS_S_CONTINUE_NEEDED) {
- snprintf(errbuf, sizeof(errbuf),
+ if (maj_stat != (OM_uint32)GSS_S_COMPLETE &&
+ maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED) {
+ snprintf(errbuf, SIZEOF(errbuf),
"error accepting context: %s", gss_error(maj_stat, min_stat));
amfree(recv_tok.value);
goto out;
amfree(recv_tok.value);
if (send_tok.length > 0 && send_token(kc, 0, &send_tok) < 0) {
- strncpy(errbuf, kc->errmsg, sizeof(errbuf) - 1);
- errbuf[sizeof(errbuf) - 1] = '\0';
+ strncpy(errbuf, kc->errmsg, SIZEOF(errbuf) - 1);
+ errbuf[SIZEOF(errbuf) - 1] = '\0';
amfree(kc->errmsg);
gss_release_buffer(&min_stat, &send_tok);
goto out;
* If we need to get more from the client, then register for
* more packets.
*/
- if (maj_stat != GSS_S_CONTINUE_NEEDED)
+ if (maj_stat != (OM_uint32)GSS_S_CONTINUE_NEEDED)
break;
}
maj_stat = gss_display_name(&min_stat, gss_name, &send_tok, &doid);
- if (maj_stat != GSS_S_COMPLETE) {
- snprintf(errbuf, sizeof(errbuf),
+ if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
+ snprintf(errbuf, SIZEOF(errbuf),
"can't display gss name: %s", gss_error(maj_stat, min_stat));
gss_release_name(&min_stat, &gss_name);
goto out;
/* get rid of the realm */
if ((p = strchr(send_tok.value, '@')) == NULL) {
- snprintf(errbuf, sizeof(errbuf),
+ snprintf(errbuf, SIZEOF(errbuf),
"malformed gss name: %s", (char *)send_tok.value);
amfree(send_tok.value);
goto out;
* If the principal doesn't match, complain
*/
if ((msg = krb5_checkuser(kc->hostname, send_tok.value, realm)) != NULL) {
- snprintf(errbuf, sizeof(errbuf),
+ snprintf(errbuf, SIZEOF(errbuf),
"access not allowed from %s: %s", (char *)send_tok.value, msg);
amfree(send_tok.value);
goto out;
* Setup some things about krb5. This should only be called once.
*/
static void
-init()
+init(void)
{
static int beenhere = 0;
struct hostent *he;
char *p;
- int krb5_setenv P((const char *, const char *, int));
if (beenhere)
return;
beenhere = 1;
#ifndef BROKEN_MEMORY_CCACHE
- krb5_setenv(KRB5_ENV_CCNAME, "MEMORY:amanda_ccache", 1);
+ setenv(KRB5_ENV_CCNAME, "MEMORY:amanda_ccache", 1);
#else
/*
* MEMORY ccaches seem buggy and cause a lot of internal heap
atexit(cleanup);
{
char ccache[64];
- snprintf(ccache, sizeof(ccache), "FILE:/tmp/amanda_ccache.%ld.%ld",
+ snprintf(ccache, SIZEOF(ccache), "FILE:/tmp/amanda_ccache.%ld.%ld",
(long)geteuid(), (long)getpid());
- krb5_setenv(KRB5_ENV_CCNAME, ccache, 1);
+ setenv(KRB5_ENV_CCNAME, ccache, 1);
}
#endif
- gethostname(hostname, sizeof(hostname) - 1);
- hostname[sizeof(hostname) - 1] = '\0';
+ gethostname(hostname, SIZEOF(hostname) - 1);
+ hostname[SIZEOF(hostname) - 1] = '\0';
/*
* In case it isn't fully qualified, do a DNS lookup.
*/
if ((he = gethostbyname(hostname)) != NULL)
- strncpy(hostname, he->h_name, sizeof(hostname) - 1);
+ strncpy(hostname, he->h_name, SIZEOF(hostname) - 1);
/*
* Lowercase the results. We assume all host/ principals will be
#ifdef BROKEN_MEMORY_CCACHE
static void
-cleanup()
+cleanup(void)
{
#ifdef KDESTROY_VIA_UNLINK
char ccache[64];
- snprintf(ccache, sizeof(ccache), "/tmp/amanda_ccache.%ld.%ld",
+ snprintf(ccache, SIZEOF(ccache), "/tmp/amanda_ccache.%ld.%ld",
(long)geteuid(), (long)getpid());
unlink(ccache);
#else
* Get a ticket granting ticket and stuff it in the cache
*/
static const char *
-get_tgt(keytab_name, principal_name)
- char *keytab_name, *principal_name;
+get_tgt(
+ char * keytab_name,
+ char * principal_name)
{
krb5_context context;
krb5_error_code ret;
return (error);
}
- krb5_init_ets(context);
+ /*krb5_init_ets(context);*/
if(!keytab_name) {
error = vstralloc("error -- no krb5 keytab defined", NULL);
return (error);
}
- memset(&creds, 0, sizeof(creds));
+ memset(&creds, 0, SIZEOF(creds));
creds.times.starttime = 0;
creds.times.endtime = now + AMANDA_TKT_LIFETIME;
/*
* get rid of tickets
*/
-kdestroy()
+static void
+kdestroy(void)
{
krb5_context context;
krb5_ccache ccache;
return;
}
-static void
-parse_pkt(pkt, buf, bufsize)
- pkt_t *pkt;
- const void *buf;
- size_t bufsize;
-{
- const unsigned char *bufp = buf;
-
- k5printf(("krb5: parse_pkt: parsing buffer of %d bytes\n", bufsize));
-
- pkt->type = (pktype_t)*bufp++;
- bufsize--;
-
- if (bufsize == 0) {
- pkt->body[0] = '\0';
- } else {
- if (bufsize > sizeof(pkt->body) - 1)
- bufsize = sizeof(pkt->body) - 1;
- memcpy(pkt->body, bufp, bufsize);
- pkt->body[sizeof(pkt->body) - 1] = '\0';
- }
-
- k5printf(("krb5: parse_pkt: %s (%d): \"%s\"\n", pkt_type2str(pkt->type),
- pkt->type, pkt->body));
-}
-
-
/*
* Formats an error from the gss api
*/
static const char *
-gss_error(major, minor)
- OM_uint32 major, minor;
+gss_error(
+ OM_uint32 major,
+ OM_uint32 minor)
{
static gss_buffer_desc msg;
OM_uint32 min_stat, msg_ctx;
* Encryption must be done by the caller.
*/
static int
-send_token(kc, handle, tok)
- struct krb5_conn *kc;
- int handle;
- const gss_buffer_desc *tok;
+send_token(
+ struct krb5_conn * kc,
+ int handle,
+ const gss_buffer_desc * tok)
{
OM_uint32 netlength, nethandle;
struct iovec iov[3];
* 32 bit handle (network byte order)
* data
*/
- netlength = htonl(tok->length);
+ netlength = (OM_uint32)htonl(tok->length);
iov[0].iov_base = (void *)&netlength;
- iov[0].iov_len = sizeof(netlength);
+ iov[0].iov_len = SIZEOF(netlength);
- nethandle = htonl(handle);
+ nethandle = (OM_uint32)htonl((uint32_t)handle);
iov[1].iov_base = (void *)&nethandle;
- iov[1].iov_len = sizeof(nethandle);
+ iov[1].iov_len = SIZEOF(nethandle);
iov[2].iov_base = (void *)tok->value;
iov[2].iov_len = tok->length;
return (0);
}
-static int
-recv_token(kc, handle, gtok, timeout)
- struct krb5_conn *kc;
- int *handle;
- gss_buffer_desc *gtok;
- int timeout;
+static ssize_t
+recv_token(
+ struct krb5_conn * kc,
+ int * handle,
+ gss_buffer_desc * gtok,
+ int timeout)
{
- OM_uint32 netint;
+ OM_uint32 netint[2];
assert(kc->fd >= 0);
assert(gtok != NULL);
k5printf(("krb5: recv_token: reading from %s\n", kc->hostname));
- switch (net_read(kc, &netint, sizeof(netint), timeout)) {
+ switch (net_read(kc->fd, &netint, SIZEOF(netint), timeout)) {
case -1:
kc->errmsg = newvstralloc(kc->errmsg, "recv error: ", strerror(errno),
NULL);
default:
break;
}
- gtok->length = ntohl(netint);
+ gtok->length = ntohl(netint[0]);
if (gtok->length > AMANDA_MAX_TOK_SIZE) {
kc->errmsg = newstralloc(kc->errmsg, "recv error: buffer too large");
return (-1);
}
- switch (net_read(kc, &netint, sizeof(netint), timeout)) {
- case -1:
- kc->errmsg = newvstralloc(kc->errmsg, "recv error: ", strerror(errno),
- NULL);
- k5printf(("krb5 recv_token error return: %s\n", kc->errmsg));
- return (-1);
- case 0:
- gtok->length = 0;
- return (0);
- default:
- break;
- }
if (handle != NULL)
- *handle = ntohl(netint);
+ *handle = ntohl(netint[1]);
gtok->value = alloc(gtok->length);
- switch (net_read(kc, gtok->value, gtok->length, timeout)) {
+ switch (net_read(kc->fd, gtok->value, gtok->length, timeout)) {
case -1:
kc->errmsg = newvstralloc(kc->errmsg, "recv error: ", strerror(errno),
NULL);
k5printf(("krb5: recv_token: read %d bytes from %s\n", gtok->length,
kc->hostname));
- return (gtok->length);
+ return ((ssize_t)gtok->length);
}
#ifdef AMANDA_KRB5_ENCRYPT
static int
-kencrypt(ks, tok, enctok)
- struct krb5_stream *ks;
- gss_buffer_desc *tok, *enctok;
+kencrypt(
+ struct krb5_stream *ks,
+ gss_buffer_desc * tok,
+ gss_buffer_desc * enctok)
{
int conf_state;
OM_uint32 maj_stat, min_stat;
assert(ks->kc->gss_context != GSS_C_NO_CONTEXT);
maj_stat = gss_seal(&min_stat, ks->kc->gss_context, 1,
GSS_C_QOP_DEFAULT, tok, &conf_state, enctok);
- if (maj_stat != GSS_S_COMPLETE || conf_state == 0) {
+ if (maj_stat != (OM_uint32)GSS_S_COMPLETE || conf_state == 0) {
security_stream_seterror(&ks->secstr,
"krb5 encryption failed to %s: %s",
ks->kc->hostname, gss_error(maj_stat, min_stat));
}
static int
-kdecrypt(ks, enctok, tok)
- struct krb5_stream *ks;
- gss_buffer_desc *enctok, *tok;
+kdecrypt(
+ struct krb5_stream *ks,
+ gss_buffer_desc * enctok,
+ gss_buffer_desc * tok)
{
OM_uint32 maj_stat, min_stat;
int conf_state, qop_state;
assert(ks->kc->gss_context != GSS_C_NO_CONTEXT);
maj_stat = gss_unseal(&min_stat, ks->kc->gss_context, enctok, tok,
&conf_state, &qop_state);
- if (maj_stat != GSS_S_COMPLETE) {
+ if (maj_stat != (OM_uint32)GSS_S_COMPLETE) {
security_stream_seterror(&ks->secstr, "krb5 decrypt error from %s: %s",
ks->kc->hostname, gss_error(maj_stat, min_stat));
return (-1);
}
#endif
-/*
- * Writes out the entire iovec
- */
-static int
-net_writev(fd, iov, iovcnt)
- int fd, iovcnt;
- struct iovec *iov;
-{
- int delta, n, total;
-
- assert(iov != NULL);
-
- total = 0;
- while (iovcnt > 0) {
- /*
- * Write the iovec
- */
- total += n = writev(fd, iov, iovcnt);
- if (n < 0)
- return (-1);
- if (n == 0) {
- errno = EIO;
- return (-1);
- }
- /*
- * Iterate through each iov. Figure out what we still need
- * to write out.
- */
- for (; n > 0; iovcnt--, iov++) {
- /* 'delta' is the bytes written from this iovec */
- delta = n < iov->iov_len ? n : iov->iov_len;
- /* subtract from the total num bytes written */
- n -= delta;
- assert(n >= 0);
- /* subtract from this iovec */
- iov->iov_len -= delta;
- (char *)iov->iov_base += delta;
- /* if this iovec isn't empty, run the writev again */
- if (iov->iov_len > 0)
- break;
- }
- }
- return (total);
-}
-
-/*
- * Like read(), but waits until the entire buffer has been filled.
- */
-static ssize_t
-net_read(kc, vbuf, origsize, timeout)
- struct krb5_conn *kc;
- void *vbuf;
- size_t origsize;
- int timeout;
-{
- char *buf = vbuf, *off; /* ptr arith */
- int nread;
- size_t size = origsize;
-
- while (size > 0) {
- if (kc->readbuf.left == 0) {
- if (net_read_fillbuf(kc, timeout) < 0)
- return (-1);
- if (kc->readbuf.size == 0)
- return (0);
- }
- nread = min(kc->readbuf.left, size);
- off = kc->readbuf.buf + kc->readbuf.size - kc->readbuf.left;
- memcpy(buf, off, nread);
-
- buf += nread;
- size -= nread;
- kc->readbuf.left -= nread;
- }
- return ((ssize_t)origsize);
-}
-
-/*
- * net_read likes to do a lot of little reads. Buffer it.
- */
-static int
-net_read_fillbuf(kc, timeout)
- struct krb5_conn *kc;
- int timeout;
-{
- fd_set readfds;
- struct timeval tv;
-
- FD_ZERO(&readfds);
- FD_SET(kc->fd, &readfds);
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
- switch (select(kc->fd + 1, &readfds, NULL, NULL, &tv)) {
- case 0:
- errno = ETIMEDOUT;
- /* FALLTHROUGH */
- case -1:
- return (-1);
- case 1:
- assert(FD_ISSET(kc->fd, &readfds));
- break;
- default:
- assert(0);
- break;
- }
- kc->readbuf.left = 0;
- kc->readbuf.size = read(kc->fd, kc->readbuf.buf,
- sizeof(kc->readbuf.buf));
-k5printf(("net_read_fillbuf: read %d characters w/ errno %d\n", kc->readbuf.size, errno));
- if (kc->readbuf.size < 0)
- return (-1);
- kc->readbuf.left = kc->readbuf.size;
- return (0);
-}
-
/*
* hackish, but you can #undef AMANDA_PRINCIPAL here, and you can both
* hardcode a principal in your build and use the .k5amandahosts. This is
* hardcoded, then we don't check the realm
*/
static char *
-krb5_checkuser(host, name, realm)
- char *host, *name, *realm;
+krb5_checkuser( char * host,
+ char * name,
+ char * realm)
{
#ifdef AMANDA_PRINCIPAL
if(strcmp(name, AMANDA_PRINCIPAL) == 0) {
if(strcmp(name, CLIENT_LOGIN) != 0) {
result = vstralloc(name, " does not match ",
CLIENT_LOGIN, NULL);
- goto common_exit;
+ return result;
}
result = NULL;
goto common_exit;
k5printf(("opening ptmp: %s\n", (ptmp)?ptmp: "NULL!"));
if((fp = fopen(ptmp, "r")) == NULL) {
result = vstralloc("can not open ", ptmp, NULL);
- goto common_exit;
+ return result;
}
k5printf(("opened ptmp\n"));
if (fstat(fileno(fp), &sbuf) != 0) {
result = vstralloc("cannot fstat ", ptmp, ": ", strerror(errno), NULL);
goto common_exit;
-
}
if (sbuf.st_uid != localuid) {
- snprintf(n1, sizeof(n1), "%ld", (long) sbuf.st_uid);
- snprintf(n2, sizeof(n2), "%ld", (long) localuid);
+ snprintf(n1, SIZEOF(n1), "%ld", (long) sbuf.st_uid);
+ snprintf(n2, SIZEOF(n2), "%ld", (long) localuid);
result = vstralloc(ptmp, ": ",
"owned by id ", n1,
", should be ", n2,
goto common_exit;
}
- while((line = agets(fp)) != NULL) {
+ while ((line = agets(fp)) != NULL) {
+ if (line[0] == '\0') {
+ amfree(line);
+ continue;
+ }
+
#if defined(SHOW_SECURITY_DETAIL) /* { */
k5printf(("%s: processing line: <%s>\n", debug_prefix(NULL), line));
#endif /* } */
continue;
}
result = NULL;
+ amfree(line);
goto common_exit;
}
-
amfree(line);
}
-
result = vstralloc("no match in ", ptmp, NULL);
common_exit:
- if(fp)
- afclose(fp);
- if(line)
- amfree(line);
+ afclose(fp);
return(result);
#endif /* AMANDA_PRINCIPAL */
}
#else
-void krb5_security_dummy (void) {}
+
+void krb5_security_dummy(void);
+
+void
+krb5_security_dummy(void)
+{
+}
+
#endif /* KRB5_SECURITY */