Commit 54bc15c4 authored by Leigh Stoller's avatar Leigh Stoller

Middle part of the event system changes. The main part of this change

is to add HMACs to events to ensure they that events cannot be
injected into an experiment by an unauthorized client.

* The frontend now generates a secret key for each experiment and
  stores that into a file and in the DB.

* Each of the event clients, as well as the event producers
  (scheduler, tevc) have a new -k option to specify the name of the
  file. Two new event library functions were added for clients to give
  the key:

    event_handle_t
    event_register_withkeyfile(char *name, int threaded, char *keyfile);

    event_handle_t
    event_register_withkeydata(char *name, int threaded,
	   		       unsigned char *keydata, int keylen);

* When the library is in possesion of a key, it will generate an HMAC
  and attach it to outgoing notifications. A client receiving a
  notification will compute an HMAC and compare it against the HMAC in
  the notification. If they do not compare, the notification is
  dropped with a warning message printed (the client callback never
  gets the notification). If the client has not provided a key, then
  the HMAC in the incoming notification is ignored.

* The scheduler also takes a -k option, and will compute HMACs for all
  of the static events ahead of time. That keeps it off the critical
  path.

* The tevc client also takes a -k option. However, tevc will always
  try to find the keyfile (default path) so that it can attach the
  HMAC to dynamic events before sending them to the scheduler (which
  will check to make sure it matches). The scheduler will not accept
  dynamic events without unless the HMAC is present and matches.

* I have rebuilt the elvin librarys, removing all of the X goop and
  the SSL goop. Smaller binaries. So, I had to add -lcrypto to all of
  the client makefiles to that programs link.

* The program-agent got a few more changes. The command string is no
  longer passed inside the event; it comes in when the program agent
  is started, via a config file generated from tmcd data. This gets
  rid of our mostly insecure remote execution facility.
parent bf5b43d3
......@@ -13,9 +13,9 @@ include $(OBJDIR)/Makeconf
SYSTEM := $(shell uname -s)
SUBDIRS = lib tbgen trafgen program-agent
SUBDIRS = lib tbgen trafgen program-agent proxy example
ifeq ($(SYSTEM),FreeBSD)
SUBDIRS += sched example delay-agent nsetrafgen stated proxy
SUBDIRS += sched delay-agent nsetrafgen stated
endif
all: $(SUBDIRS)
......@@ -60,21 +60,18 @@ install:
@$(MAKE) -C stated install
client-install:
ifeq ($(SYSTEM),FreeBSD)
@$(MAKE) -C nsetrafgen client-install
@$(MAKE) -C delay-agent client-install
@$(MAKE) -C program-agent client-install
endif
@$(MAKE) -C tbgen client-install
@$(MAKE) -C program-agent client-install
@$(MAKE) -C trafgen client-install
@$(MAKE) -C proxy client-install
control-install:
@$(MAKE) -C tbgen control-install
linux-install:
@$(MAKE) -C program-agent client-install
@$(MAKE) -C tbgen client-install
@$(MAKE) -C trafgen client-install
clean: subdir-clean
subdir-clean:
......
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002 University of Utah and the Flux Group.
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
# All rights reserved.
#
......@@ -22,7 +22,7 @@ CFLAGS += `elvin-config --cflags vin4c`
LDFLAGS += -static
LDFLAGS += -L../lib -L${OBJDIR}/lib/libtb
LIBS += -levent -ltb
LIBS += -levent -ltb -lcrypto
LIBS += `elvin-config --libs vin4c`
OBJS = main.o callback.o
......
......@@ -75,6 +75,7 @@ int main(int argc, char **argv)
char *map_file = NULL;
char *log_file = "/tmp/agentlog";
char *pid_file = NULL;
char *keyfile = NULL;
FILE *mp = NULL;
//char *log = NULL;
char buf[BUFSIZ];
......@@ -86,7 +87,7 @@ int main(int argc, char **argv)
opterr = 0;
/* get params from the optstring */
while ((c = getopt(argc, argv, "s:p:f:dE:l:i:")) != -1) {
while ((c = getopt(argc, argv, "s:p:f:dE:l:i:k:")) != -1) {
switch (c) {
case 'd':
debug++;
......@@ -109,6 +110,9 @@ int main(int argc, char **argv)
case 'E':
myexp = optarg;
break;
case 'k':
keyfile = optarg;
break;
case '?':
default:
usage(argv[0]);
......@@ -274,7 +278,7 @@ int main(int argc, char **argv)
/* register with the event system*/
handle = event_register(server, 0);
handle = event_register_withkeyfile(server, 0, keyfile);
if (handle == NULL) {
error("could not register with event system\n");
return 1;
......@@ -319,7 +323,8 @@ void usage(char *progname)
info("entering function usage\n");
#endif
fprintf(stderr, "Usage: %s -s server [-p port] -f link-map-file\n",
fprintf(stderr, "Usage: %s -s server [-p port] [-k keyfile] "
"-f link-map-file\n",
progname);
exit(-1);
}
......
......@@ -3,6 +3,7 @@ TESTBED_SRCDIR = @top_srcdir@
OBJDIR = ../..
SUBDIR = event/example
SYSTEM := $(shell uname -s)
PROGRAMS = tbrecv tbsend eventdebug.pl
include $(OBJDIR)/Makeconf
......@@ -17,8 +18,11 @@ CFLAGS += -I. -I${OBJDIR} -I$(SRCDIR)/../lib -I$(TESTBED_SRCDIR)/lib/libtb
CFLAGS += `elvin-config --cflags vin4c`
LDFLAGS += -static -L../lib -L${OBJDIR}/lib/libtb
LIBS += -levent -ltb
LIBS += -levent -ltb -lcrypto
LIBS += `elvin-config --libs vin4c`
ifeq ($(SYSTEM),Linux)
LIBS += -ldl
endif
tbrecv: tbrecv.o
$(CC) $(LDFLAGS) -o $@ tbrecv.o $(LIBS)
......
......@@ -25,7 +25,7 @@ void
usage()
{
fprintf(stderr,
"Usage: %s [-s server] [-p port]\n", progname);
"Usage: %s [-s server] [-p port] [-k keyfile]\n", progname);
exit(-1);
}
......@@ -35,6 +35,7 @@ main(int argc, char **argv)
event_handle_t handle;
address_tuple_t tuple;
char *server = NULL;
char *keyfile = NULL;
char *port = NULL;
char *ipaddr = NULL;
char buf[BUFSIZ], ipbuf[BUFSIZ];
......@@ -42,7 +43,7 @@ main(int argc, char **argv)
progname = argv[0];
while ((c = getopt(argc, argv, "s:p:i:")) != -1) {
while ((c = getopt(argc, argv, "s:p:k:")) != -1) {
switch (c) {
case 's':
server = optarg;
......@@ -50,6 +51,9 @@ main(int argc, char **argv)
case 'p':
port = optarg;
break;
case 'k':
keyfile = optarg;
break;
default:
usage();
}
......@@ -114,7 +118,7 @@ main(int argc, char **argv)
/*
* Register with the event system.
*/
handle = event_register(server, 0);
handle = event_register_withkeyfile(server, 0, keyfile);
if (handle == NULL) {
fatal("could not register with event system");
}
......
......@@ -22,7 +22,7 @@ void
usage()
{
fprintf(stderr,
"Usage: %s [-s server] [-p port] <event>\n",
"Usage: %s [-s server] [-p port] [-k keyfile] <event>\n",
progname);
exit(-1);
}
......@@ -35,13 +35,14 @@ main(int argc, char **argv)
address_tuple_t tuple;
char *server = NULL;
char *port = NULL;
char *keyfile = NULL;
char buf[BUFSIZ], *bp;
struct timeval now;
int c;
progname = argv[0];
while ((c = getopt(argc, argv, "s:p:")) != -1) {
while ((c = getopt(argc, argv, "s:p:k:")) != -1) {
switch (c) {
case 's':
server = optarg;
......@@ -49,6 +50,9 @@ main(int argc, char **argv)
case 'p':
port = optarg;
break;
case 'k':
keyfile = optarg;
break;
default:
usage();
}
......@@ -95,7 +99,7 @@ main(int argc, char **argv)
tuple->host = ADDRESSTUPLE_ALL;
/* Register with the event system: */
handle = event_register(server, 0);
handle = event_register_withkeyfile(server, 0, keyfile);
if (handle == NULL) {
fatal("could not register with event system");
}
......
......@@ -12,9 +12,9 @@ SUBDIR = event/lib
include $(OBJDIR)/Makeconf
SYSTEM := $(shell uname -s)
PROGRAMS = libevent.a libevent_r.a
PROGRAMS = libevent.a
ifneq ($(SYSTEM),Linux)
PROGRAMS += event.so
PROGRAMS += libevent_r.a event.so
endif
all: $(PROGRAMS)
......@@ -22,10 +22,11 @@ all: $(PROGRAMS)
include $(TESTBED_SRCDIR)/GNUmakerules
#CFLAGS += -DDEBUG
CFLAGS += -O -g -static -I. -Wall -I$(TESTBED_SRCDIR)/lib/libtb
CFLAGS += `elvin-config --cflags vin4mt`
CFLAGS += -O2 -g -static -I. -Wall -I$(TESTBED_SRCDIR)/lib/libtb
SCFLAGS = $(CFLAGS) `elvin-config --cflags vin4c`
TCFLAGS = $(CFLAGS) `elvin-config --cflags vin4mt`
# Special CFLAGS w/o warnings, for SWIG-generated code
CFLAGS_NOWARN += -O -g -static -I. -I$(TESTBED_SRCDIR)/lib/libtb
CFLAGS_NOWARN += -O2 -g -static -I. -I$(TESTBED_SRCDIR)/lib/libtb
CFLAGS_NOWARN += `elvin-config --cflags vin4mt`
LDFLAGS += -L${OBJDIR}/lib/libtb
......@@ -45,7 +46,12 @@ $(OBJS): event.h
$(POBJS): event.h
event_r.o: event.c
$(CC) $(CFLAGS) -DTHREADED -c -o event_r.o $<
$(CC) $(TCFLAGS) -DTHREADED -c -o event_r.o $<
event.o: event.c
$(CC) $(SCFLAGS) -c -o event.o $<
util.o: util.c
$(CC) $(SCFLAGS) -c -o util.o $<
#
# These three targets are for the perl binding to the event system
......@@ -59,7 +65,7 @@ event_wrap.o: $(SRCDIR)/event_wrap.c
event.so: event.o event_wrap.o util.o
ld -shared $^ $(OBJDIR)/lib/libtb/libtb.a \
`elvin-config --libs vin4c` -o event.so
`elvin-config --libs vin4c` -lcrypto -o event.so
LIB_STUFF = event.pm event.so
......@@ -67,4 +73,4 @@ install: $(addprefix $(INSTALL_LIBDIR)/, $(LIB_STUFF))
clean:
/bin/rm -f *.o libevent.a *.so *.pm
/bin/rm -f *.o libevent.a libevent_r.a *.so *.pm
To isolate the pain of building threaded (and statically linked) event
system programs, we build two versions of the event library, one for
non threaded programs and another (libevent_r.a) for threaded
versions. Threaded clients require a bunch of extra link goo, but at
the moment the only threaded client is the event scheduler. If you
try and use the threaded API without the proper link, the library will
print an error message and quit.
......@@ -19,6 +19,8 @@
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/param.h>
#include <time.h>
#include "event.h"
#include "log.h"
......@@ -29,6 +31,9 @@
#define TRACE(fmt,...)
#endif
static int event_notification_check_hmac(event_handle_t handle,
event_notification_t notification);
static char hostname[MAXHOSTNAMELEN];
static char ipaddr[32];
......@@ -63,9 +68,44 @@ static int handles_in_use = 0;
* is NULL, then Elvin's server discovery protocol will be used to find
* the Elvin server.
*/
event_handle_t
event_register(char *name, int threaded)
{
return event_register_withkeydata(name, threaded, NULL, 0);
}
event_handle_t
event_register_withkeyfile(char *name, int threaded, char *keyfile)
{
/* Grab the key data and stick it into the handle. */
if (keyfile) {
FILE *fp;
unsigned char buf[2*BUFSIZ];
int cc;
if ((fp = fopen(keyfile, "r")) == NULL) {
ERROR("could not open keyfile: %s", keyfile);
return 0;
}
if ((cc = fread(buf, sizeof(char), sizeof(buf), fp)) == 0) {
ERROR("could not read keyfile: %s", keyfile);
fclose(fp);
return 0;
}
if (cc == sizeof(buf)) {
ERROR("keyfile is too big: %s", keyfile);
fclose(fp);
return 0;
}
fclose(fp);
return event_register_withkeydata(name, threaded, buf, cc);
}
return event_register_withkeydata(name, threaded, NULL, 0);
}
event_handle_t
event_register_withkeydata(char *name, int threaded,
unsigned char *keydata, int keylen)
{
event_handle_t handle;
elvin_handle_t server;
......@@ -92,6 +132,15 @@ event_register(char *name, int threaded)
/* Allocate a handle to be returned to the caller: */
handle = xmalloc(sizeof(*handle));
bzero(handle, sizeof(*handle));
/* Grab the key data and stick it into the handle. */
if (keydata) {
handle->keydata = xmalloc(keylen + 1);
handle->keylen = keylen;
memcpy(handle->keydata, keydata, keylen);
handle->keydata[keylen] = (unsigned char)0;
}
/* Set up the Elvin interface pointers: */
if (threaded) {
......@@ -105,8 +154,7 @@ event_register(char *name, int threaded)
handle->subscribe = elvin_threaded_add_subscription;
#else
ERROR("Threaded API not linked in with the program!\n");
free(handle);
return 0;
goto bad;
#endif
} else {
handle->init = elvin_sync_init_default;
......@@ -123,15 +171,13 @@ event_register(char *name, int threaded)
status = handle->init();
if (status == NULL) {
ERROR("could not initialize Elvin\n");
free(handle);
return 0;
goto bad;
}
server = elvin_handle_alloc(status);
if (server == NULL) {
ERROR("elvin_handle_alloc failed: ");
elvin_error_fprintf(stderr, status);
free(handle);
return 0;
goto bad;
}
/* Set the discovery scope to "testbed", so that we only interact
......@@ -139,8 +185,7 @@ event_register(char *name, int threaded)
if (elvin_handle_set_discovery_scope(server, "testbed", status) == 0) {
ERROR("elvin_handle_set_discovery_scope failed: ");
elvin_error_fprintf(stderr, status);
free(handle);
return 0;
goto bad;
}
/* Set the server URL, if we were passed one by the user. */
......@@ -148,8 +193,7 @@ event_register(char *name, int threaded)
if (elvin_handle_append_url(server, name, status) == 0) {
ERROR("elvin_handle_append_url failed: ");
elvin_error_fprintf(stderr, status);
free(handle);
return 0;
goto bad;
}
}
......@@ -157,8 +201,7 @@ event_register(char *name, int threaded)
if (handle->connect(server, status) == 0) {
ERROR("could not connect to Elvin server: ");
elvin_error_fprintf(stderr, status);
free(handle);
return 0;
goto bad;
}
handle->server = server;
......@@ -168,8 +211,13 @@ event_register(char *name, int threaded)
* Keep track of how many handles we have outstanding
*/
handles_in_use++;
return handle;
bad:
if (handle->keydata)
free(handle->keydata);
free(handle);
return 0;
}
......@@ -219,6 +267,8 @@ event_unregister(event_handle_t handle)
handles_in_use--;
if (handle->keydata)
free(handle->keydata);
free(handle);
return 1;
......@@ -273,6 +323,7 @@ internal_event_poll(event_handle_t handle, int blocking, unsigned int timeout)
*/
if (timeout && elvin_timeout) {
elvin_error_t error;
elvin_error_clear(error);
elvin_sync_remove_timeout(elvin_timeout, error);
}
......@@ -349,13 +400,17 @@ event_notify(event_handle_t handle, event_notification_t notification)
ERROR("invalid parameter\n");
return 0;
}
if (handle->keydata && !notification->has_hmac &&
event_notification_insert_hmac(handle, notification)) {
return 0;
}
TRACE("sending event notification %p\n", notification);
/* Send notification to Elvin server for routing: */
if (handle->notify(handle->server, notification, 1, NULL, handle->status)
== 0)
{
if (handle->notify(handle->server, notification->elvin_notification,
1, NULL, handle->status)
== 0) {
ERROR("could not send event notification: ");
elvin_error_fprintf(stderr, handle->status);
return 0;
......@@ -438,21 +493,28 @@ event_schedule(event_handle_t handle, event_notification_t notification,
event_notification_t
event_notification_alloc(event_handle_t handle, address_tuple_t tuple)
{
elvin_notification_t notification;
event_notification_t notification;
elvin_notification_t elvin_notification;
if (!handle || !tuple) {
if (!handle) {
ERROR("invalid paramater\n");
return NULL;
}
TRACE("allocating notification (tuple=%p)\n", tuple);
notification = elvin_notification_alloc(handle->status);
if (notification == NULL) {
notification = xmalloc(sizeof(event_notification_t));
elvin_notification = elvin_notification_alloc(handle->status);
if (elvin_notification == NULL) {
ERROR("elvin_notification_alloc failed: ");
elvin_error_fprintf(stderr, handle->status);
return NULL;
}
notification->elvin_notification = elvin_notification;
notification->has_hmac = 0;
if (tuple == NULL)
return notification;
TRACE("allocated notification %p\n", notification);
#define EVPUT(name, field) \
......@@ -474,7 +536,6 @@ event_notification_alloc(event_handle_t handle, address_tuple_t tuple)
ERROR("could not add attributes to notification %p\n", notification);
return NULL;
}
/* Add our address */
event_notification_set_sender(handle, notification, ipaddr);
......@@ -491,18 +552,20 @@ int
event_notification_free(event_handle_t handle,
event_notification_t notification)
{
if (!handle || !notification) {
if (!handle || !notification || !notification->elvin_notification) {
ERROR("invalid parameter\n");
return 0;
}
TRACE("freeing notification %p\n", notification);
if (elvin_notification_free(notification, handle->status) == 0) {
if (elvin_notification_free(notification->elvin_notification,
handle->status) == 0) {
ERROR("elvin_notification_free failed: ");
elvin_error_fprintf(stderr, handle->status);
return 0;
}
free(notification);
return 1;
}
......@@ -517,18 +580,23 @@ event_notification_clone(event_handle_t handle,
{
event_notification_t clone;
if (!handle || !notification) {
if (!handle || !notification || !notification->elvin_notification) {
ERROR("invalid parameter\n");
return 0;
}
TRACE("cloning notification %p\n", notification);
if (! (clone = elvin_notification_clone(notification, handle->status)) ) {
clone = xmalloc(sizeof(event_notification_t));
if (! (clone->elvin_notification =
elvin_notification_clone(notification->elvin_notification,
handle->status))) {
ERROR("elvin_notification_clone failed: ");
elvin_error_fprintf(stderr, handle->status);
free(clone);
return 0;
}
clone->has_hmac = notification->has_hmac;
return clone;
......@@ -567,10 +635,9 @@ event_notification_get(event_handle_t handle,
/* attr_traverse returns 0 to indicate that it has found the
desired attribute. */
if (elvin_notification_traverse(notification, attr_traverse, &arg,
handle->status)
== 0)
{
if (elvin_notification_traverse(notification->elvin_notification,
attr_traverse, &arg, handle->status)
== 0) {
/* Found it. */
return 1;
}
......@@ -753,8 +820,8 @@ event_notification_put_double(event_handle_t handle,
TRACE("adding attribute (name=\"%s\", value=%f) to notification %p\n",
name, value, notification);
if (elvin_notification_add_real64(notification, name, value,
handle->status)
if (elvin_notification_add_real64(notification->elvin_notification,
name, value, handle->status)
== 0)
{
ERROR("elvin_notification_add_real64 failed: ");
......@@ -785,8 +852,8 @@ event_notification_put_int32(event_handle_t handle,
TRACE("adding attribute (name=\"%s\", value=%d) to notification %p\n",
name, value, notification);
if (elvin_notification_add_int32(notification, name, value,
handle->status)
if (elvin_notification_add_int32(notification->elvin_notification,
name, value, handle->status)
== 0)
{
ERROR("elvin_notification_add_int32 failed: ");
......@@ -817,8 +884,8 @@ event_notification_put_int64(event_handle_t handle,
TRACE("adding attribute (name=\"%s\", value=%lld) to notification %p\n",
name, value, notification);
if (elvin_notification_add_int64(notification, name, value,
handle->status)
if (elvin_notification_add_int64(notification->elvin_notification,
name, value, handle->status)
== 0)
{
ERROR("elvin_notification_add_int64 failed: ");
......@@ -850,8 +917,8 @@ event_notification_put_opaque(event_handle_t handle,
TRACE("adding attribute (name=\"%s\", value=<opaque>) "
"to notification %p\n", name, notification);
if (elvin_notification_add_opaque(notification, name, buffer, length,
handle->status)
if (elvin_notification_add_opaque(notification->elvin_notification,
name, buffer, length, handle->status)
== 0)
{
ERROR("elvin_notification_add_opaque failed: ");
......@@ -882,8 +949,8 @@ event_notification_put_string(event_handle_t handle,
TRACE("adding attribute (name=\"%s\", value=\"%s\") to notification %p\n",
name, value, notification);
if (elvin_notification_add_string(notification, name, value,
handle->status)
if (elvin_notification_add_string(notification->elvin_notification,
name, value, handle->status)
== 0)
{
ERROR("elvin_notification_add_string failed: ");
......@@ -913,7 +980,8 @@ event_notification_remove(event_handle_t handle,
TRACE("removing attribute \"%s\" from notification %p\n",
name, notification);
if (elvin_notification_remove(notification, name, handle->status) == 0) {
if (elvin_notification_remove(notification->elvin_notification,
name, handle->status) == 0) {
ERROR("elvin_notification_remove failed: ");
elvin_error_fprintf(stderr, handle->status);
return 0;
......@@ -926,6 +994,7 @@ event_notification_remove(event_handle_t handle,
struct notify_callback_arg {
event_notify_callback_t callback;
void *data;
event_handle_t handle;
};
static void notify_callback(elvin_handle_t server,
......@@ -1076,6 +1145,7 @@ event_subscribe(event_handle_t handle, event_notify_callback_t callback,
/* XXX: Free this in an event_unsubscribe.. */
arg->callback = callback;
arg->data = data;
arg->handle = handle;
subscription = handle->subscribe(handle->server, expression, NULL, 1,
notify_callback, arg, handle->status);
......@@ -1118,27 +1188,43 @@ attr_traverse(void *rock, char *name, elvin_basetypes_t type,
* Callback passed to handle->subscribe in event_subscribe. Used to
* provide our own callback above Elvin's.
*/
static void
notify_callback(elvin_handle_t server,
elvin_subscription_t subscription,
elvin_notification_t notification, int is_secure,
elvin_notification_t elvin_notification, int is_secure,
void *rock, elvin_error_t status)
{
struct event_handle handle;
struct notify_callback_arg *arg = (struct notify_callback_arg *) rock;
struct event_notification notification;
event_handle_t handle;
event_notify_callback_t callback;
void *data;
TRACE("received event notification\n");
assert(arg);
notification.elvin_notification = elvin_notification;
notification.has_hmac = 0;
handle = arg->handle;
/* If MAC does not match, throw it away */
if (handle->keydata &&
event_notification_check_hmac(handle, &notification)) {
return;
}
if (0) {
struct timeval now;
gettimeofday(&now, NULL);
info("note arrived at %ld:%d\n", now.tv_sec, now.tv_usec);
}
callback = arg->callback;
data = arg->data;
handle.server = server;
handle.status = status;
callback(&handle, notification, data);
callback(handle, &notification, data);
}
/*
......@@ -1160,3 +1246,177 @@ address_tuple_free(address_tuple_t tuple)
free(tuple);
return 1;
}
/*
* Insert an HMAC into the notifcation.
*/
#include <openssl/hmac.h>
/*
* The traversal function callback. Add to the hmac for each attribute.
*/
static int
hmac_traverse(void *rock, char *name, elvin_basetypes_t type,
elvin_value_t value, elvin_error_t status)
{
HMAC_CTX *ctx = (HMAC_CTX *) rock;
/*
* Do not include hmac in hmac computation!
*/
if (!strcmp(name, "__hmac__"))
return 1;
switch (type) {
case ELVIN_INT32:
HMAC_Update(ctx, (unsigned char *)&(value.i), sizeof(value.i));
break;
case ELVIN_INT64:
HMAC_Update(ctx, (unsigned char *)&(value.h), sizeof(value.h));
break;
case ELVIN_REAL64:
HMAC_Update(ctx, (unsigned char *)&(value.d), sizeof(value.d));
break;
case ELVIN_STRING:
HMAC_Update(ctx, (unsigned char *)(value.s), strlen(value.s));
break;
case ELVIN_OPAQUE:
HMAC_Update(ctx, (unsigned char *)(value.o.data),
value.o.length);
break;
default:
ERROR("invalid parameter\n");
return 0;
}
return 1;
}
int
event_notification_insert_hmac(event_handle_t handle,
event_notification_t notification)
{
HMAC_CTX ctx;
unsigned char mac[EVP_MAX_MD_SIZE];
int i, len = EVP_MAX_MD_SIZE;
if (0)
info("event_notification_insert_hmac: %d %s\n",
handle->keylen, handle->keydata);
if (notification->has_hmac) {
event_notification_remove(handle, notification, "__hmac__");
notification->has_hmac = 0;
}
memset(&ctx, 0, sizeof(ctx));