Implement RFC 2104 HMAC Keyed Hashing.
Implement RFC 3118 Authentication for DHCP Messages
and RFC 3315 Authentication options.
include config.mk
CFLAGS+= -std=${CSTD}
+SRCS+= ${DHCPCD_SRCS}
+
+.PATH: ./crypt
+
+VPATH= . ./crypt
+
+CPPFLAGS+= -I./crypt
+SRCS+= auth.c hmac_md5.c ${MD5_SRC}
+
OBJS+= ${SRCS:.c=.o} ${COMPAT_SRCS:.c=.o}
SCRIPT= ${LIBEXECDIR}/dhcpcd-run-hooks
CLEANFILES+= *.tar.bz2
-.PHONY: import import-bsd dev
+.PHONY: import import-bsd dev test
.SUFFIXES: .in
${PROG}: ${DEPEND} ${OBJS}
${CC} ${LDFLAGS} -o $@ ${OBJS} ${LDADD}
+test:
+ cd $@; ${MAKE} $@; ./$@
+
_embeddedinstall: dhcpcd-definitions.conf
${INSTALL} -d ${DESTDIR}${SCRIPTSDIR}
${INSTALL} -m ${CONFMODE} dhcpcd-definitions.conf ${DESTDIR}${SCRIPTSDIR}
clean:
rm -f ${OBJS} ${PROG} ${PROG}.core ${CLEANFILES}
- for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
+ for x in ${SUBDIRS} test; do cd $$x; ${MAKE} $@; cd ..; done
distclean: clean
rm -f .depend config.h config.mk
if (++state->claims < ANNOUNCE_NUM)
syslog(LOG_DEBUG,
"%s: sending ARP announce (%d of %d), "
- "next in %d.00 seconds",
+ "next in %d.0 seconds",
ifp->name, state->claims, ANNOUNCE_NUM, ANNOUNCE_WAIT);
else
syslog(LOG_DEBUG,
eloop_timeout_add_tv(&tv, dhcp_bind, ifp);
}
syslog(LOG_DEBUG,
- "%s: sending ARP probe (%d of %d), next in %0.2f seconds",
+ "%s: sending ARP probe (%d of %d), next in %0.1f seconds",
ifp->name, state->probes ? state->probes : PROBE_NUM, PROBE_NUM,
timeval_to_double(&tv));
if (arp_send(ifp, ARPOP_REQUEST, 0, addr.s_addr) == -1)
--- /dev/null
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/file.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+#include "config.h"
+#include "auth.h"
+#include "crypt/crypt.h"
+#include "dhcp.h"
+#include "dhcp6.h"
+#include "dhcpcd.h"
+
+#ifndef htonll
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+static inline uint64_t
+htonll(uint64_t x)
+{
+
+ return (uint64_t)htonl((uint32_t)(x >> 32)) |
+ (int64_t)htonl((uint32_t)(x & 0xffffffff)) << 32;
+}
+#else /* (BYTE_ORDER == LITTLE_ENDIAN) */
+#define htonll(x) (x)
+#endif
+#endif /* htonll */
+
+#ifndef ntohll
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+static inline uint64_t
+ntohll(uint64_t x)
+{
+
+ return (uint64_t)ntohl((uint32_t)(x >> 32)) |
+ (int64_t)ntohl((uint32_t)(x & 0xffffffff)) << 32;
+}
+#else /* (BYTE_ORDER == LITTLE_ENDIAN) */
+#define ntohll(x) (x)
+#endif
+#endif /* ntohll */
+
+#define HMAC_LENGTH 16
+
+/*
+ * Authenticate a DHCP message.
+ * m and mlen refer to the whole message.
+ * t is the DHCP type, pass it 4 or 6.
+ * data and dlen refer to the authentication option within the message.
+ */
+const struct token *
+dhcp_auth_validate(struct authstate *state, const struct auth *auth,
+ const uint8_t *m, unsigned int mlen, int mp, int mt,
+ const uint8_t *data, unsigned int dlen)
+{
+ uint8_t protocol, algorithm, rdm, *mm, type;
+ uint64_t replay;
+ uint32_t secretid;
+ const uint8_t *d, *realm;
+ unsigned int realm_len;
+ const struct token *t;
+ time_t now;
+ uint8_t hmac[HMAC_LENGTH];
+
+ if (dlen < 3 + sizeof(replay)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* Ensure that d is inside m which *may* not be the case for DHPCPv4 */
+ if (data < m || data > m + mlen || data + dlen > m + mlen) {
+ errno = ERANGE;
+ return NULL;
+ }
+
+ d = data;
+ protocol = *d++;
+ algorithm = *d++;
+ rdm = *d++;
+ if (!(auth->options & DHCPCD_AUTH_SEND)) {
+ /* If we didn't send any authorisation, it can only be a
+ * reconfigure key */
+ if (protocol != AUTH_PROTO_RECONFKEY) {
+ errno = EINVAL;
+ return NULL;
+ }
+ } else if (protocol != auth->protocol ||
+ algorithm != auth->algorithm ||
+ rdm != auth->rdm)
+ {
+ errno = EPERM;
+ return NULL;
+ }
+
+ dlen -= 3;
+ memcpy(&replay, d, sizeof(replay));
+ replay = ntohll(replay);
+ d+= sizeof(replay);
+ dlen -= sizeof(replay);
+
+ if (state->token && replay - state->replay <= 0) {
+ /* Replay attack detected */
+ errno = EPERM;
+ return NULL;
+ }
+
+ realm = NULL;
+ realm_len = 0;
+
+ /* Extract realm and secret.
+ * Rest of data is MAC. */
+ switch (protocol) {
+ case AUTH_PROTO_TOKEN:
+ secretid = 0;
+ break;
+ case AUTH_PROTO_DELAYED:
+ if (dlen < sizeof(secretid) + sizeof(hmac)) {
+ errno = EINVAL;
+ return NULL;
+ }
+ memcpy(&secretid, d, sizeof(secretid));
+ d += sizeof(secretid);
+ dlen -= sizeof(secretid);
+ break;
+ case AUTH_PROTO_DELAYEDREALM:
+ if (dlen < sizeof(secretid) + sizeof(hmac)) {
+ errno = EINVAL;
+ return NULL;
+ }
+ realm_len = dlen - (sizeof(secretid) + sizeof(hmac));
+ if (realm_len) {
+ realm = d;
+ d += realm_len;
+ dlen -= realm_len;
+ }
+ memcpy(&secretid, d, sizeof(secretid));
+ d += sizeof(secretid);
+ dlen -= sizeof(secretid);
+ break;
+ case AUTH_PROTO_RECONFKEY:
+ if (dlen != 1 + 16) {
+ errno = EINVAL;
+ return NULL;
+ }
+ type = *d++;
+ dlen--;
+ switch (type) {
+ case 1:
+ if ((mp == 4 && mt == DHCP_ACK) ||
+ (mp == 6 && mt == DHCP6_REPLY))
+ {
+ if (state->reconf == NULL) {
+ state->reconf =
+ malloc(sizeof(*state->reconf));
+ if (state->reconf == NULL)
+ return NULL;
+ state->reconf->key = malloc(16);
+ if (state->reconf->key == NULL) {
+ free(state->reconf);
+ state->reconf = NULL;
+ return NULL;
+ }
+ state->reconf->secretid = 0;
+ state->reconf->expire = 0;
+ state->reconf->realm = NULL;
+ state->reconf->realm_len = 0;
+ state->reconf->key_len = 16;
+ }
+ memcpy(state->reconf->key, d, 16);
+ } else {
+ errno = EINVAL;
+ return NULL;
+ }
+ if (state->reconf == NULL)
+ errno = ENOENT;
+ /* Nothing to validate, just accepting the key */
+ return state->reconf;
+ case 2:
+ if (state->reconf == NULL) {
+ errno = ENOENT;
+ return NULL;
+ }
+ t = state->reconf;
+ goto gottoken;
+ default:
+ errno = EINVAL;
+ return NULL;
+ }
+ default:
+ errno = ENOTSUP;
+ return NULL;
+ }
+
+ /* Find a token for the realm and secret */
+ secretid = ntohl(secretid);
+ TAILQ_FOREACH(t, &auth->tokens, next) {
+ if (t->secretid == secretid &&
+ t->realm_len == realm_len &&
+ (t->realm_len == 0 ||
+ memcmp(t->realm, realm, t->realm_len) == 0))
+ break;
+ }
+ if (t == NULL) {
+ errno = ESRCH;
+ return NULL;
+ }
+ if (t->expire) {
+ if (time(&now) == -1)
+ return NULL;
+ if (t->expire < now) {
+ errno = EFAULT;
+ return NULL;
+ }
+ }
+
+gottoken:
+ /* First message from the server */
+ if (state->token && state->token != t) {
+ errno = EPERM;
+ return NULL;
+ }
+
+ /* Special case as no hashing needs to be done. */
+ if (protocol == AUTH_PROTO_TOKEN) {
+ if (dlen != t->key_len || memcmp(d, t->key, dlen)) {
+ errno = EPERM;
+ return NULL;
+ }
+ goto finish;
+ }
+
+ /* Make a duplicate of the message, but zero out the MAC part */
+ mm = malloc(mlen);
+ if (mm == NULL)
+ return NULL;
+ memcpy(mm, m, mlen);
+ memset(mm + (d - m), 0, dlen);
+
+ /* RFC3318, section 5.2 - zero giaddr and hops */
+ if (mp == 4) {
+ *(mm + offsetof(struct dhcp_message, hwopcount)) = '\0';
+ memset(mm + offsetof(struct dhcp_message, giaddr), 0, 4);
+ }
+
+ memset(hmac, 0, sizeof(hmac));
+ switch (algorithm) {
+ case AUTH_ALG_HMAC_MD5:
+ hmac_md5(mm, mlen, t->key, t->key_len, hmac);
+ break;
+ default:
+ errno = ENOSYS;
+ free(mm);
+ return NULL;
+ }
+
+ free(mm);
+ if (memcmp(d, &hmac, dlen)) {
+ errno = EPERM;
+ return NULL;
+ }
+
+finish:
+ /* If we got here then authentication passed */
+ state->replay = replay;
+ state->token = t;
+
+ return t;
+}
+
+static uint64_t last_rdm;
+static uint8_t last_rdm_set;
+static uint64_t
+get_next_rdm_monotonic(void)
+{
+ FILE *fp;
+ char *line, *ep;
+ uint64_t rdm;
+ int flocked;
+
+ fp = fopen(RDM_MONOFILE, "r+");
+ if (fp == NULL) {
+ if (errno != ENOENT)
+ return ++last_rdm; /* report error? */
+ fp = fopen(RDM_MONOFILE, "w");
+ if (fp == NULL)
+ return ++last_rdm; /* report error? */
+ flocked = flock(fileno(fp), LOCK_EX);
+ rdm = 0;
+ } else {
+ flocked = flock(fileno(fp), LOCK_EX);
+ line = get_line(fp);
+ if (line == NULL)
+ rdm = 0; /* truncated? report error? */
+ else
+ rdm = strtoull(line, &ep, 0);
+ }
+
+ rdm++;
+ fseek(fp, 0, SEEK_SET);
+ if (fprintf(fp, "0x%016" PRIu64 "\n", rdm) != 19) {
+ if (!last_rdm_set) {
+ last_rdm = rdm;
+ last_rdm_set = 1;
+ } else
+ rdm = ++last_rdm;
+ /* report error? */
+ }
+ fflush(fp);
+ if (flocked == 0)
+ flock(fileno(fp), LOCK_UN);
+ fclose(fp);
+ return rdm;
+}
+
+
+/*
+ * Encode a DHCP message.
+ * Either we know which token to use from the server response
+ * or we are using a basic configuration token.
+ * token is the token to encrypt with.
+ * m and mlen refer to the whole message.
+ * mp is the DHCP type, pass it 4 or 6.
+ * mt is the DHCP message type.
+ * data and dlen refer to the authentication option within the message.
+ */
+int
+dhcp_auth_encode(const struct auth *auth, const struct token *t,
+ uint8_t *m, unsigned int mlen, int mp, int mt,
+ uint8_t *data, unsigned int dlen)
+{
+ uint64_t rdm;
+ uint8_t hmac[HMAC_LENGTH];
+ time_t now;
+ uint8_t hops, *p;
+ uint32_t giaddr, secretid;
+
+ if (auth->protocol == 0 && t == NULL) {
+ TAILQ_FOREACH(t, &auth->tokens, next) {
+ if (t->secretid == 0 &&
+ t->realm_len == 0)
+ break;
+ }
+ if (t == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (t->expire) {
+ if (time(&now) == -1)
+ return -1;
+ if (t->expire < now) {
+ errno = EPERM;
+ return -1;
+ }
+ }
+ }
+
+ switch(auth->protocol) {
+ case AUTH_PROTO_TOKEN:
+ case AUTH_PROTO_DELAYED:
+ case AUTH_PROTO_DELAYEDREALM:
+ /* We don't ever send a reconf key */
+ break;
+ default:
+ errno = ENOTSUP;
+ return -1;
+ }
+
+ switch(auth->algorithm) {
+ case AUTH_ALG_HMAC_MD5:
+ break;
+ default:
+ errno = ENOTSUP;
+ return -1;
+ }
+
+ switch(auth->rdm) {
+ case AUTH_RDM_MONOTONIC:
+ break;
+ default:
+ errno = ENOTSUP;
+ return -1;
+ }
+
+ /* Work out the auth area size.
+ * We only need to do this for DISCOVER messages */
+ if (data == NULL) {
+ dlen = 1 + 1 + 1 + 8;
+ switch(auth->protocol) {
+ case AUTH_PROTO_TOKEN:
+ dlen += t->key_len;
+ break;
+ case AUTH_PROTO_DELAYEDREALM:
+ if (t)
+ dlen += t->realm_len;
+ /* FALLTHROUGH */
+ case AUTH_PROTO_DELAYED:
+ if (t)
+ dlen += sizeof(t->secretid) + sizeof(hmac);
+ break;
+ }
+ return dlen;
+ }
+
+ if (dlen < 1 + 1 + 1 + 8) {
+ errno = ENOBUFS;
+ return -1;
+ }
+
+ /* Ensure that d is inside m which *may* not be the case for DHPCPv4 */
+ if (data < m || data > m + mlen || data + dlen > m + mlen) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ /* Write out our option */
+ *data++ = auth->protocol;
+ *data++ = auth->algorithm;
+ *data++ = auth->rdm;
+ switch (auth->rdm) {
+ case AUTH_RDM_MONOTONIC:
+ rdm = get_next_rdm_monotonic();
+ break;
+ default:
+ /* This block appeases gcc, clang doesn't need it */
+ rdm = get_next_rdm_monotonic();
+ break;
+ }
+ rdm = htonll(rdm);
+ memcpy(data, &rdm, 8);
+ data += 8;
+ dlen -= 1 + 1 + 1 + 8;
+
+ /* Special case as no hashing needs to be done. */
+ if (auth->protocol == AUTH_PROTO_TOKEN) {
+ /* Should be impossible, but still */
+ if (t == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (dlen < t->key_len) {
+ errno = ENOBUFS;
+ return -1;
+ }
+ memcpy(data, t->key, t->key_len);
+ return dlen - t->key_len;
+ }
+
+ /* DISCOVER or INFORM messages don't write auth info */
+ if ((mp == 4 && (mt == DHCP_DISCOVER || mt == DHCP_INFORM)) ||
+ (mp == 6 && (mt == DHCP6_SOLICIT || mt == DHCP6_INFORMATION_REQ)))
+ return dlen;
+
+ /* Loading a saved lease without an authentication option */
+ if (t == NULL)
+ return 0;
+
+ /* Write out the Realm */
+ if (auth->protocol == AUTH_PROTO_DELAYEDREALM) {
+ if (dlen < t->realm_len) {
+ errno = ENOBUFS;
+ return -1;
+ }
+ memcpy(data, t->realm, t->realm_len);
+ data += t->realm_len;
+ dlen -= t->realm_len;
+ }
+
+ /* Write out the SecretID */
+ if (auth->protocol == AUTH_PROTO_DELAYED ||
+ auth->protocol == AUTH_PROTO_DELAYEDREALM)
+ {
+ if (dlen < sizeof(t->secretid)) {
+ errno = ENOBUFS;
+ return -1;
+ }
+ secretid = htonl(t->secretid);
+ memcpy(data, &secretid, sizeof(secretid));
+ data += sizeof(secretid);
+ dlen -= sizeof(secretid);
+ }
+
+ /* Zero what's left, the MAC */
+ memset(data, 0, dlen);
+
+ /* RFC3318, section 5.2 - zero giaddr and hops */
+ if (mp == 4) {
+ p = m + offsetof(struct dhcp_message, hwopcount);
+ hops = *p;
+ *p = '\0';
+ p = m + offsetof(struct dhcp_message, giaddr);
+ memcpy(&giaddr, p, sizeof(giaddr));
+ memset(p, 0, sizeof(giaddr));
+ } else {
+ /* appease GCC again */
+ hops = 0;
+ giaddr = 0;
+ }
+
+ /* Create our hash and write it out */
+ switch(auth->algorithm) {
+ case AUTH_ALG_HMAC_MD5:
+ hmac_md5(m, mlen, t->key, t->key_len, hmac);
+ memcpy(data, hmac, sizeof(hmac));
+ break;
+ }
+
+ /* RFC3318, section 5.2 - restore giaddr and hops */
+ if (mp == 4) {
+ p = m + offsetof(struct dhcp_message, hwopcount);
+ *p = hops;
+ p = m + offsetof(struct dhcp_message, giaddr);
+ memcpy(p, &giaddr, sizeof(giaddr));
+ }
+
+ /* Done! */
+ return dlen - sizeof(hmac); /* should be zero */
+}
--- /dev/null
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef AUTH_H
+#define AUTH_H
+
+#include <sys/queue.h>
+
+#define DHCPCD_AUTH_SEND (1 << 0)
+#define DHCPCD_AUTH_REQUIRE (1 << 1)
+
+#define AUTH_PROTO_TOKEN 0
+#define AUTH_PROTO_DELAYED 1
+#define AUTH_PROTO_DELAYEDREALM 2
+#define AUTH_PROTO_RECONFKEY 3
+
+#define AUTH_ALG_HMAC_MD5 1
+
+#define AUTH_RDM_MONOTONIC 0
+
+struct token {
+ TAILQ_ENTRY(token) next;
+ uint32_t secretid;
+ unsigned int realm_len;
+ unsigned char *realm;
+ unsigned int key_len;
+ unsigned char *key;
+ time_t expire;
+};
+
+TAILQ_HEAD(token_head, token);
+
+struct auth {
+ int options;
+ uint8_t protocol;
+ uint8_t algorithm;
+ uint8_t rdm;
+ struct token_head tokens;
+};
+
+struct authstate {
+ uint64_t replay;
+ const struct token *token;
+ struct token *reconf;
+};
+
+const struct token * dhcp_auth_validate(struct authstate *,
+ const struct auth *,
+ const uint8_t *, unsigned int, int, int,
+ const uint8_t *, unsigned int);
+
+int dhcp_auth_encode(const struct auth *, const struct token *,
+ uint8_t *, unsigned int, int, int,
+ uint8_t *, unsigned int);
+#endif
--without-posix_spawn) POSIX_SPAWN=no;;
--without-pollts) POLLTS=no;;
--with-pollts) POLLTS=$var;;
+ --without-md5) MD5=no;;
--without-dev) DEV=no;;
--without-udev) UDEV=no;;
--serviceexists) SERVICEEXISTS=$var;;
if [ -z "$EMBEDDED" -o "$EMBEDDED" = yes ]; then
echo "dhcpcd-definitions.conf will be embedded in dhcpcd itself"
- echo "SRCS+= dhcpcd-embedded.c" >>$CONFIG_MK
+ echo "DHCPCD_SRCS+= dhcpcd-embedded.c" >>$CONFIG_MK
else
echo "dhcpcd-definitions.conf will be installed to $LIBEXECDIR"
echo "CFLAGS+= -DEMBEDDED_CONFIG=\\\"$LIBEXECDIR/dhcpcd-definitions.conf\\\"" >>$CONFIG_MK
linux)
echo "CPPFLAGS+= -D_BSD_SOURCE -D_XOPEN_SOURCE=700" >>$CONFIG_MK
if [ -z "$INET" -o "$INET" = yes ]; then
- echo "SRCS+= lpf.c" >>$CONFIG_MK
+ echo "DHCPCD_SRCS+= lpf.c" >>$CONFIG_MK
fi
- echo "SRCS+= if-linux.c if-linux-wireless.c" >>$CONFIG_MK
- echo "SRCS+= platform-linux.c" >>$CONFIG_MK
+ echo "DHCPCD_SRCS+= if-linux.c if-linux-wireless.c" >>$CONFIG_MK
+ echo "DHCPCD_SRCS+= platform-linux.c" >>$CONFIG_MK
echo "LDADD+= -lrt -ldl" >>$CONFIG_MK
;;
kfreebsd)
echo "CPPFLAGS+= -D_GNU_SOURCE" >>$CONFIG_MK
if [ -z "$INET" -o "$INET" = yes ]; then
- echo "SRCS+= bpf.c" >>$CONFIG_MK
+ echo "DHCPCD_SRCS+= bpf.c" >>$CONFIG_MK
fi
- echo "SRCS+= if-bsd.c platform-bsd.c" >>$CONFIG_MK
+ echo "DHCPCD_SRCS+= if-bsd.c platform-bsd.c" >>$CONFIG_MK
echo "COMPAT_SRCS+= compat/linkaddr.c" >>$CONFIG_MK
echo "LDADD+= -lrt -ldl" >>$CONFIG_MK
;;
*)
if [ -z "$INET" -o "$INET" = yes ]; then
- echo "SRCS+= bpf.c" >>$CONFIG_MK
+ echo "DHCPCD_SRCS+= bpf.c" >>$CONFIG_MK
fi
- echo "SRCS+= if-bsd.c platform-bsd.c" >>$CONFIG_MK
+ echo "DHCPCD_SRCS+= if-bsd.c platform-bsd.c" >>$CONFIG_MK
;;
esac
if [ -z "$INET" -o "$INET" = yes ]; then
echo "CPPFLAGS+= -DINET" >>$CONFIG_MK
- echo "SRCS+= arp.c dhcp.c ipv4.c ipv4ll.c" >>$CONFIG_MK
+ echo "DHCPCD_SRCS+= arp.c dhcp.c ipv4.c ipv4ll.c" >>$CONFIG_MK
fi
if [ -z "$INET6" -o "$INET6" = yes ]; then
echo "CPPFLAGS+= -DINET6" >>$CONFIG_MK
- echo "SRCS+= ipv6.c ipv6nd.c dhcp6.c" >>$CONFIG_MK
+ echo "DHCPCD_SRCS+= ipv6.c ipv6nd.c dhcp6.c" >>$CONFIG_MK
fi
# NetBSD: Even if we build for $PREFIX, the clueless user might move us to /
;;
esac
+if [ -z "$MD5" ]; then
+ printf "Testing for MD5Init ... "
+ cat <<EOF >_md5.c
+#include <md5.h>
+#include <stdlib.h>
+int main(void) {
+ MD5_CTX context;
+ MD5Init(&context);
+ return 0;
+}
+EOF
+ if $XCC _md5.c -o _md5 2>/dev/null; then
+ MD5=yes
+ else
+ MD5=no
+ fi
+ echo "$MD5"
+ rm -f _md5.c _md5
+fi
+if [ "$MD5" = no ]; then
+ echo "MD5_SRC= md5.c" >>$CONFIG_MK
+else
+ echo "MD5_SRC=" >>$CONFIG_MK
+ echo "CPPFLAGS+= -DHAVE_MD5H" >>$CONFIG_H
+fi
+
if [ "$DEV" != no -a "$UDEV" != no ]; then
printf "Checking for libudev ... "
LIBUDEV_CFLAGS=$(pkg-config --cflags libudev 2>/dev/null)
fi
if [ "$DEV" = yes ]; then
- echo "SRCS+= dev.c" >>$CONFIG_MK
+ echo "DHCPCD_SRCS+= dev.c" >>$CONFIG_MK
echo "CPPFLAGS+= -DPLUGIN_DEV" >>$CONFIG_MK
echo "MKDIRS+= dev" >>$CONFIG_MK
fi
echo " MANDIR = $MANDIR"
echo " HOOKSCRIPTS = $HOOKS"
echo
+
+rm -f dhcpcd tests/test
--- /dev/null
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef CRYPT_H
+#define CRYPT_H
+
+void hmac_md5(const uint8_t *, int, const uint8_t *, int, uint8_t *);
+
+#endif
--- /dev/null
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <inttypes.h>
+#include <string.h>
+
+#include "crypt.h"
+
+#ifdef HAVE_MD5_H
+#include <md5.h>
+#else
+#include "md5.h"
+#endif
+
+#define HMAC_PAD_LEN 64
+#define IPAD 0x36
+#define OPAD 0x5C
+
+/* hmac_md5 as per RFC3118 */
+void
+hmac_md5(const uint8_t *text, int text_len,
+ const uint8_t *key, int key_len,
+ uint8_t *digest)
+{
+ uint8_t k_ipad[HMAC_PAD_LEN], k_opad[HMAC_PAD_LEN];
+ uint8_t tk[MD5_DIGEST_LENGTH];
+ int i;
+ MD5_CTX context;
+
+ /* Ensure key is no bigger than HMAC_PAD_LEN */
+ if (key_len > HMAC_PAD_LEN) {
+ MD5Init(&context);
+ MD5Update(&context, key, key_len);
+ MD5Final(tk, &context);
+ key = tk;
+ key_len = MD5_DIGEST_LENGTH;
+ }
+
+ /* store key in pads */
+ memcpy(k_ipad, key, key_len);
+ memcpy(k_opad, key, key_len);
+ memset(k_ipad + key_len, 0, sizeof(k_ipad) - key_len);
+ memset(k_opad + key_len, 0, sizeof(k_opad) - key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i = 0; i < HMAC_PAD_LEN; i++) {
+ k_ipad[i] ^= IPAD;
+ k_opad[i] ^= OPAD;
+ }
+
+ /* inner MD5 */
+ MD5Init(&context);
+ MD5Update(&context, k_ipad, HMAC_PAD_LEN);
+ MD5Update(&context, text, text_len);
+ MD5Final(digest, &context);
+
+ /* outer MD5 */
+ MD5Init(&context);
+ MD5Update(&context, k_opad, HMAC_PAD_LEN);
+ MD5Update(&context, digest, MD5_DIGEST_LENGTH);
+ MD5Final(digest, &context);
+}
--- /dev/null
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include <sys/param.h>
+#include <inttypes.h>
+
+#include <string.h>
+
+#include "md5.h"
+
+#define PUT_64BIT_LE(cp, value) do { \
+ (cp)[7] = (value) >> 56; \
+ (cp)[6] = (value) >> 48; \
+ (cp)[5] = (value) >> 40; \
+ (cp)[4] = (value) >> 32; \
+ (cp)[3] = (value) >> 24; \
+ (cp)[2] = (value) >> 16; \
+ (cp)[1] = (value) >> 8; \
+ (cp)[0] = (value); } while (0)
+
+#define PUT_32BIT_LE(cp, value) do { \
+ (cp)[3] = (value) >> 24; \
+ (cp)[2] = (value) >> 16; \
+ (cp)[1] = (value) >> 8; \
+ (cp)[0] = (value); } while (0)
+
+static uint8_t PADDING[MD5_BLOCK_LENGTH] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(MD5_CTX *ctx)
+{
+ ctx->count = 0;
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xefcdab89;
+ ctx->state[2] = 0x98badcfe;
+ ctx->state[3] = 0x10325476;
+}
+
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void
+MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_LENGTH])
+{
+ uint32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4];
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ memcpy(in, block, sizeof(in));
+#else
+ for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) {
+ in[a] = (uint32_t)(
+ (uint32_t)(block[a * 4 + 0]) |
+ (uint32_t)(block[a * 4 + 1]) << 8 |
+ (uint32_t)(block[a * 4 + 2]) << 16 |
+ (uint32_t)(block[a * 4 + 3]) << 24);
+ }
+#endif
+
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+
+ MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21);
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(MD5_CTX *ctx, const unsigned char *input, size_t len)
+{
+ size_t have, need;
+
+ /* Check how many bytes we already have and how many more we need. */
+ have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1));
+ need = MD5_BLOCK_LENGTH - have;
+
+ /* Update bitcount */
+ ctx->count += (uint64_t)len << 3;
+
+ if (len >= need) {
+ if (have != 0) {
+ memcpy(ctx->buffer + have, input, need);
+ MD5Transform(ctx->state, ctx->buffer);
+ input += need;
+ len -= need;
+ have = 0;
+ }
+
+ /* Process data in MD5_BLOCK_LENGTH-byte chunks. */
+ while (len >= MD5_BLOCK_LENGTH) {
+ MD5Transform(ctx->state, input);
+ input += MD5_BLOCK_LENGTH;
+ len -= MD5_BLOCK_LENGTH;
+ }
+ }
+
+ /* Handle any remaining bytes of data. */
+ if (len != 0)
+ memcpy(ctx->buffer + have, input, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx)
+{
+ uint8_t count[8];
+ size_t padlen;
+ int i;
+
+ /* Convert count to 8 bytes in little endian order. */
+ PUT_64BIT_LE(count, ctx->count);
+
+ /* Pad out to 56 mod 64. */
+ padlen = MD5_BLOCK_LENGTH -
+ ((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1));
+ if (padlen < 1 + 8)
+ padlen += MD5_BLOCK_LENGTH;
+ MD5Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */
+ MD5Update(ctx, count, 8);
+
+ if (digest != NULL) {
+ for (i = 0; i < 4; i++)
+ PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
+ }
+ memset(ctx, 0, sizeof(*ctx)); /* in case it's sensitive */
+}
+
+
--- /dev/null
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#ifndef MD5_H_
+#define MD5_H_
+
+#define MD5_DIGEST_LENGTH 16
+#define MD5_BLOCK_LENGTH 64
+
+typedef struct MD5Context {
+ uint32_t state[4]; /* state (ABCD) */
+ uint64_t count; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[MD5_BLOCK_LENGTH]; /* input buffer */
+} MD5_CTX;
+
+void MD5Init(MD5_CTX *);
+void MD5Update(MD5_CTX *, const unsigned char *, size_t);
+void MD5Final(unsigned char[MD5_DIGEST_LENGTH], MD5_CTX *);
+#endif
#ifndef CONTROLSOCKET
# define CONTROLSOCKET RUNDIR "/" PACKAGE ".sock"
#endif
+#ifndef RDM_MONOFILE
+# define RDM_MONOFILE DBDIR "/" PACKAGE "-rdm.monotonic"
+#endif
#endif
uint8_t type)
{
struct dhcp_message *dhcp;
- uint8_t *m, *lp, *p;
+ uint8_t *m, *lp, *p, *auth;
uint8_t *n_params = NULL;
uint32_t ul;
uint16_t sz;
size_t len, i;
+ int auth_len;
const struct dhcp_opt *opt;
const struct if_options *ifo = iface->options;
const struct dhcp_state *state = D_CSTATE(iface);
}
*n_params = p - n_params - 1;
}
+
+ /* silence GCC */
+ auth_len = 0;
+ auth = NULL;
+
+ if (ifo->auth.options & DHCPCD_AUTH_SEND) {
+ auth_len = dhcp_auth_encode(&ifo->auth, state->auth.token,
+ NULL, 0, 4, type, NULL, 0);
+ if (auth_len > 0) {
+ len = (p + auth_len) - m;
+ if (auth_len > 255 || len > sizeof(*dhcp))
+ goto toobig;
+ *p++ = DHO_AUTHENTICATION;
+ *p++ = (uint8_t)auth_len;
+ auth = p;
+ p += auth_len;
+ } else if (auth_len == -1)
+ syslog(LOG_ERR, "%s: dhcp_auth_encode: %m",
+ iface->name);
+ }
+
*p++ = DHO_END;
#ifdef BOOTP_MESSAGE_LENTH_MIN
*p++ = DHO_PAD;
#endif
+ len = p - m;
+ if (ifo->auth.options & DHCPCD_AUTH_SEND && auth_len > 0)
+ dhcp_auth_encode(&ifo->auth, state->auth.token,
+ m, len, 4, type, auth, auth_len);
+
*message = dhcp;
- return p - m;
+ return len;
toobig:
syslog(LOG_ERR, "%s: DHCP messge too big", iface->name);
}
struct dhcp_message *
-read_lease(const struct interface *ifp)
+read_lease(struct interface *ifp)
{
int fd;
struct dhcp_message *dhcp;
- const struct dhcp_state *state = D_CSTATE(ifp);
+ struct dhcp_state *state = D_STATE(ifp);
ssize_t bytes;
+ const uint8_t *auth;
+ uint8_t type;
+ int auth_len;
fd = open(state->leasefile, O_RDONLY);
if (fd == -1) {
close(fd);
if (bytes < 0) {
free(dhcp);
- dhcp = NULL;
+ return NULL;
}
+
+ /* We may have found a BOOTP server */
+ if (get_option_uint8(&type, dhcp, DHO_MESSAGETYPE) == -1)
+ type = 0;
+ /* Authenticate the message */
+ auth = get_option(dhcp, DHO_AUTHENTICATION, &auth_len);
+ if (auth) {
+ if (dhcp_auth_validate(&state->auth, &ifp->options->auth,
+ (uint8_t *)dhcp, sizeof(*dhcp), 4, type,
+ auth, auth_len) == NULL)
+ {
+ syslog(LOG_DEBUG, "%s: dhcp_auth_validate: %m",
+ ifp->name);
+ free(dhcp);
+ return NULL;
+ }
+ syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32,
+ ifp->name, state->auth.token->secretid);
+ }
+
return dhcp;
}
tv.tv_usec = arc4random() % (DHCP_RAND_MAX_U - DHCP_RAND_MIN_U);
timernorm(&tv);
syslog(LOG_DEBUG,
- "%s: sending %s (xid 0x%x), next in %0.2f seconds",
+ "%s: sending %s (xid 0x%x), next in %0.1f seconds",
iface->name, get_dhcp_op(type), state->xid,
timeval_to_double(&tv));
}
state->old = NULL;
state->lease.addr.s_addr = 0;
ifp->options->options &= ~ DHCPCD_CSR_WARNED;
+ state->auth.token = NULL;
+ state->auth.replay = 0;
+ free(state->auth.reconf);
+ state->auth.reconf = NULL;
}
static void
struct dhcp_message *dhcp = *dhcpp;
struct dhcp_lease *lease = &state->lease;
uint8_t type, tmp;
+ const uint8_t *auth;
struct in_addr addr;
size_t i;
-
- /* reset the message counter */
- state->interval = 0;
+ int auth_len;
/* We may have found a BOOTP server */
if (get_option_uint8(&type, dhcp, DHO_MESSAGETYPE) == -1)
type = 0;
+ /* Authenticate the message */
+ auth = get_option(dhcp, DHO_AUTHENTICATION, &auth_len);
+ if (auth) {
+ if (dhcp_auth_validate(&state->auth, &ifo->auth,
+ (uint8_t *)*dhcpp, sizeof(**dhcpp), 4, type,
+ auth, auth_len) == NULL)
+ {
+ syslog(LOG_DEBUG, "%s: dhcp_auth_validate: %m",
+ iface->name);
+ log_dhcp(LOG_ERR, "authentication failed",
+ iface, dhcp, from);
+ return;
+ }
+ syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32,
+ iface->name, state->auth.token->secretid);
+ } else if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) {
+ log_dhcp(LOG_ERR, "missing authentiation", iface, dhcp, from);
+ return;
+ }
+
+ /* reset the message counter */
+ state->interval = 0;
+
if (type == DHCP_NAK) {
/* For NAK, only check if we require the ServerID */
if (has_option_mask(ifo->requiremask, DHO_SERVERID) &&
/*
* dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
#include <limits.h>
#include <stdint.h>
+#include "auth.h"
#include "dhcp-common.h"
/* UDP port numbers for DHCP */
DHO_USERCLASS = 77, /* RFC 3004 */
DHO_RAPIDCOMMIT = 80, /* RFC 4039 */
DHO_FQDN = 81,
+ DHO_AUTHENTICATION = 90, /* RFC 3118 */
DHO_VIVCO = 124, /* RFC 3925 */
DHO_VIVSO = 125, /* RFC 3925 */
DHO_DNSSEARCH = 119, /* RFC 3397 */
time_t start_uptime;
unsigned char *clientid;
+
+ struct authstate auth;
};
#define D_STATE(ifp) \
int valid_dhcp_packet(unsigned char *);
ssize_t write_lease(const struct interface *, const struct dhcp_message *);
-struct dhcp_message *read_lease(const struct interface *);
+struct dhcp_message *read_lease(struct interface *);
void get_lease(struct dhcp_lease *, const struct dhcp_message *);
void dhcp_handleifa(int, struct interface *,
const struct dhcp6_option *si, *unicast;
ssize_t len, ml;
size_t l;
+ int auth_len;
uint8_t u8;
- uint16_t *u16, n_options;
+ uint16_t *u16, n_options, type;
const struct if_options *ifo;
const struct dhcp_opt *opt;
uint8_t IA, *p;
m = state->new;
ml = state->new_len;
}
-
- state->send = malloc(len);
- if (state->send == NULL)
- return -1;
-
- state->send_len = len;
unicast = NULL;
/* Depending on state, get the unicast address */
switch(state->state) {
break;
case DH6S_INIT: /* FALLTHROUGH */
case DH6S_DISCOVER:
- state->send->type = DHCP6_SOLICIT;
+ type = DHCP6_SOLICIT;
break;
case DH6S_REQUEST:
- state->send->type = DHCP6_REQUEST;
+ type = DHCP6_REQUEST;
unicast = dhcp6_getmoption(D6_OPTION_UNICAST, m, ml);
break;
case DH6S_CONFIRM:
- state->send->type = DHCP6_CONFIRM;
+ type = DHCP6_CONFIRM;
break;
case DH6S_REBIND:
- state->send->type = DHCP6_REBIND;
+ type = DHCP6_REBIND;
break;
case DH6S_RENEW:
- state->send->type = DHCP6_RENEW;
+ type = DHCP6_RENEW;
unicast = dhcp6_getmoption(D6_OPTION_UNICAST, m, ml);
break;
case DH6S_INFORM:
- state->send->type = DHCP6_INFORMATION_REQ;
+ type = DHCP6_INFORMATION_REQ;
break;
case DH6S_RELEASE:
- state->send->type = DHCP6_RELEASE;
+ type = DHCP6_RELEASE;
unicast = dhcp6_getmoption(D6_OPTION_UNICAST, m, ml);
break;
default:
errno = EINVAL;
- free(state->send);
- state->send = NULL;
return -1;
}
+ if (ifo->auth.options & DHCPCD_AUTH_SEND) {
+ auth_len = dhcp_auth_encode(&ifo->auth, state->auth.token,
+ NULL, 0, 6, type, NULL, 0);
+ if (auth_len > 0)
+ len += sizeof(*o) + auth_len;
+ } else
+ auth_len = 0; /* appease GCC */
+
+ state->send = malloc(len);
+ if (state->send == NULL)
+ return -1;
+
+ state->send_len = len;
+ state->send->type = type;
+
/* If we found a unicast option, copy it to our state for sending */
if (unicast && ntohs(unicast->len) == sizeof(state->unicast.s6_addr))
memcpy(&state->unicast.s6_addr, D6_COPTION_DATA(unicast),
}
}
+ /* This has to be the last option */
+ if (ifo->auth.options & DHCPCD_AUTH_SEND && auth_len > 0) {
+ o = D6_NEXT_OPTION(o);
+ o->code = htons(D6_OPTION_AUTH);
+ o->len = htons(auth_len);
+ if (dhcp_auth_encode(&ifo->auth, state->auth.token,
+ (uint8_t *)state->send, state->send_len,
+ 6, state->send->type,
+ D6_OPTION_DATA(o), auth_len) == -1)
+ {
+ printf ("oh dear\n");
+ free(state->send);
+ state->send = NULL;
+ return -1;
+ }
+ }
+
return 0;
}
logsend:
syslog(LOG_DEBUG,
"%s: %s %s (xid 0x%02x%02x%02x),"
- " next in %0.2f seconds",
+ " next in %0.1f seconds",
ifp->name,
broad_uni,
dhcp6_get_op(state->send->type),
syslog(LOG_ERR, "%s: dhcp6_makemessage: %m", ifp->name);
return;
}
+
dhcp6_sendrequest(ifp);
}
state->MRT = CNF_MAX_RT;
state->MRC = 0;
+ syslog(LOG_INFO, "%s: confirming prior DHCPv6 lease", ifp->name);
if (dhcp6_makemessage(ifp) == -1) {
syslog(LOG_ERR, "%s: dhcp6_makemessage: %m", ifp->name);
return;
int fd;
ssize_t bytes;
struct timeval now;
+ const struct dhcp6_option *o;
state = D6_STATE(ifp);
if (stat(state->leasefile, &st) == -1) {
}
}
+ /* Authenticate the message */
+ o = dhcp6_getmoption(D6_OPTION_AUTH, state->new, state->new_len);
+ if (o) {
+ if (dhcp_auth_validate(&state->auth, &ifp->options->auth,
+ (uint8_t *)state->new, state->new_len, 6, state->new->type,
+ D6_COPTION_DATA(o), ntohs(o->len)) == NULL)
+ {
+ syslog(LOG_DEBUG, "%s: dhcp_auth_validate: %m",
+ ifp->name);
+ syslog(LOG_ERR, "%s: authentication failed",
+ ifp->name);
+ goto ex;
+ }
+ syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32,
+ ifp->name, state->auth.token->secretid);
+ } else if (ifp->options->auth.options & DHCPCD_AUTH_REQUIRE) {
+ syslog(LOG_ERR, "%s: authentication now required", ifp->name);
+ goto ex;
+ } else
+ syslog(LOG_ERR, "eg");
+
return fd;
ex:
}
}
+ /* Authenticate the message */
+ o = dhcp6_getmoption(D6_OPTION_AUTH, r, len);
+ if (o) {
+ if (dhcp_auth_validate(&state->auth, &ifo->auth,
+ (uint8_t *)r, len, 6, r->type,
+ D6_COPTION_DATA(o), ntohs(o->len)) == NULL)
+ {
+ syslog(LOG_DEBUG, "dhcp_auth_validate: %m");
+ syslog(LOG_ERR, "%s: authentication failed from %s",
+ ifp->name, sfrom);
+ return;
+ }
+ syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32,
+ ifp->name, state->auth.token->secretid);
+ } else if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) {
+ syslog(LOG_ERR, "%s: missing authentiation from %s",
+ ifp->name, sfrom);
+ return;
+ }
+
op = dhcp6_get_op(r->type);
switch(r->type) {
case DHCP6_REPLY:
free(state->recv);
free(state->new);
free(state->old);
+ free(state->auth.reconf);
free(state);
ifp->if_data[IF_DATA_DHCP6] = NULL;
}
#define D6_OPTION_IA_ADDR 5
#define D6_OPTION_PREFERENCE 7
#define D6_OPTION_ELAPSED 8
+#define D6_OPTION_AUTH 11
#define D6_OPTION_UNICAST 12
#define D6_OPTION_STATUS_CODE 13
#define D6_OPTION_RAPID_COMMIT 14
uint8_t sla_set;
char leasefile[PATH_MAX];
const char *reason;
+
+ struct authstate auth;
};
#define D6_STATE(ifp) \
define 88 domain bcms_controller_names
define 89 array ipaddress bcms_controller_address
+# DHCP Authentication, RFC3118
+define 90 embed auth
+embed byte protocol
+embed byte algorithm
+embed byte rdm
+embed binhex:8 replay
+embed binhex information
+
# DHCP Leasequery, RFC4388
define 91 uint32 client_last_transaction_time
define 92 array ipaddress associated_ip
define6 11 embed auth
embed byte protocol
embed byte algorithm
-embed binhex:8 replay_detection
+embed byte rdm
+embed binhex:8 replay
embed binhex information
define6 12 ip6address unicast
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd January 18, 2014
+.Dd January 24, 2014
.Dt DHCPCD 8
.Os
.Sh NAME
The actual DHCP message send by the server.
We use this when reading the last
lease and use the files mtime as when it was issued.
+.It Pa @DBDIR@/dhcpcd-rdm.monotonic
+Stores the monotonic counter used in the
+.Ar replay
+field in Authentication Options.
.It Pa /var/run/dhcpcd.pid
Stores the PID of
.Nm
.Xr dhcpcd-run-hooks 8 ,
.Xr resolvconf 8
.Sh STANDARDS
-RFC\ 951 RFC\ 1534 RFC\ 2131, RFC\ 2132, RFC\ 2855, RFC\ 3004, RFC\ 3315,
-RFC\ 3361, RFC\ 3633, RFC\ 3396, RFC\ 3397, RFC\ 3442, RFC\ 3495, RFC\ 3925,
-RFC\ 3927, RFC\ 4039, RFC\ 4075, RFC\ 4242, RFC\ 4361, RFC\ 4390, RFC\ 4702,
-RFC\ 4074, RFC\ 4861, RFC\ 4833, RFC\ 5227, RFC\ 5942, RFC\ 5969, RFC\ 6106.
+RFC\ 951, RFC\ 1534, RFC\ 2104, RFC\ 2131, RFC\ 2132, RFC\ 2855, RFC\ 3004,
+RFC\ 3118, RFC\ 3315, RFC\ 3361, RFC\ 3633, RFC\ 3396, RFC\ 3397, RFC\ 3442,
+RFC\ 3495, RFC\ 3925, RFC\ 3927, RFC\ 4039, RFC\ 4075, RFC\ 4242, RFC\ 4361,
+RFC\ 4390, RFC\ 4702, RFC\ 4074, RFC\ 4861, RFC\ 4833, RFC\ 5227, RFC\ 5942,
+RFC\ 5969, RFC\ 6106.
.Sh AUTHORS
.An Roy Marples Aq Mt roy@marples.name
.Sh BUGS
Please report them to
.Lk http://roy.marples.name/projects/dhcpcd
+.Pp
+If authentication is used and the
+.Pa @DBDIR@/dhcpcd-rdm.monotonic
+file is removed or altered then the DHCP server will need it's notion
+of the last replay value
+.Nm
+sent reset.
+We could change this to use a NTP time stamp instead, but it's
+more likely the RTC on this host is broken which would cause the same result.
+.Pp
+WIDE DHCPv6 server sometimes fails to authenticate a
+.Nm
+message.
}
}
#endif
+
+ /* If we are not sending an authentication option, don't require it */
+ if (!(ifo->auth.options & DHCPCD_AUTH_SEND))
+ ifo->auth.options &= ~DHCPCD_AUTH_REQUIRE;
+
}
int
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd January 18, 2014
+.Dd January 24, 2014
.Dt DHCPCD.CONF 5
.Os
.Sh NAME
.Pp
.D1 profile 192.168.0.1
.D1 static ip_address=192.168.0.10/24
+.It Ic authprotocol Ar protocol Ar algorithm Ar rdm
+Authenticate DHCP messages.
+See the Supported Protocols section.
+.It Ic authtoken Ar secretid Ar realm Ar expire Ar key
+Define a shared key for use in authentication.
+.Ar realm can be "" to for use with the
+.Ar delayed
+prptocol.
+.Ar expire
+is the date the token expires and should be formatted "yyy-mm-dd HH:MM".
+You can use the keyword
+.Ar forever
+or
+.Ar 0
+which means the token never expires.
.It Ic background
Background immediately.
This is useful for startup scripts which don't disable link messages for
.It Ic noarp
Don't send any ARP requests.
This also disables IPv4LL.
+.It Ic noauthrequired
+Don't require authentication even though we requested it.
.It Ic nodev
Don't load
.Pa /dev
.D1 embed uint32 enterprise_number
.D1 # Options defined for the enterprise number
.D1 encap 1 ipaddress ipaddress
+.Ss Supported protocols
+.Bl -tag -width -indent
+.It Ic token
+Sends and expects the token with the secretid 0 in each message.
+.It Ic delayedrealm
+Delayed Authentication.
+.Nm dhcpcd
+will send an authentication option with no key or MAC.
+The server will see this option, and select a key for
+.Nm , writing the
+.Ar realm
+and
+.Ar secretid
+in it.
+.Nm dhcpcd
+will then look for a non-expired token with a matching realm and secretid.
+This token is used to authenicate all other messages.
+.It Ic delayed
+Same as above, but without a realm.
+.El
+.Ss Supported algorithms
+If none specified,
+.Ic hmac-md5
+is the default.
+.Bl -tag -width -indent
+.It Ic hmac-md5
+.El
+.Ss Supported Replay Detection Mechanisms
+If none specified,
+.Ic monotonic
+is the default.
+.Bl -tag -width -indent
+.It Ic monotonic
+.El
.Sh SEE ALSO
.Xr fnmatch 3 ,
.Xr if_nametoindex 3 ,
#include <sys/param.h>
#include <sys/types.h>
+#include <sys/queue.h>
#include <arpa/inet.h>
#define O_ENCAP O_BASE + 22
#define O_VENDOPT O_BASE + 23
#define O_VENDCLASS O_BASE + 24
+#define O_AUTHPROTOCOL O_BASE + 25
+#define O_AUTHTOKEN O_BASE + 26
+#define O_AUTHNOTREQUIRED O_BASE + 27
char *dev_load;
{"encap", required_argument, NULL, O_ENCAP},
{"vendopt", required_argument, NULL, O_VENDOPT},
{"vendclass", required_argument, NULL, O_VENDCLASS},
+ {"authprotocol", required_argument, NULL, O_AUTHPROTOCOL},
+ {"authtoken", required_argument, NULL, O_AUTHTOKEN},
+ {"noauthrequired", no_argument, NULL, O_AUTHNOTREQUIRED},
{NULL, 0, NULL, '\0'}
};
}
static int
-parse_iaid(uint8_t *iaid, const char *arg, size_t len)
+parse_iaid1(uint8_t *iaid, const char *arg, size_t len, int n)
{
unsigned long l;
size_t s;
errno = 0;
l = strtoul(arg, &np, 0);
if (l <= (unsigned long)UINT32_MAX && errno == 0 && *np == '\0') {
- u32 = htonl(l);
+ if (n)
+ u32 = htonl(l);
+ else
+ u32 = l;
memcpy(iaid, &u32, sizeof(u32));
return 0;
}
return 0;
}
+static int
+parse_iaid(uint8_t *iaid, const char *arg, size_t len)
+{
+
+ return parse_iaid1(iaid, arg, len, 1);
+}
+
+static int
+parse_uint32(uint32_t *i, const char *arg)
+{
+
+ return parse_iaid1((uint8_t *)i, arg, sizeof(uint32_t), 0);
+}
+
static char **
splitv(int *argc, char **argv, const char *arg)
{
return UNCONST(s);
}
+/* Find the end pointer of a string. */
+static char *
+strend(const char *s)
+{
+
+ s = strskipwhite(s);
+ if (s == NULL)
+ return NULL;
+ if (*s != '"')
+ return strchr(s, ' ');
+ s++;
+ for (; *s != '"' ; s++) {
+ if (*s == '\0')
+ return NULL;
+ if (*s == '\\') {
+ if (*(++s) == '\0')
+ return NULL;
+ }
+ }
+ return UNCONST(++s);
+}
+
static int
parse_option(const char *ifname, struct if_options *ifo,
int opt, const char *arg)
struct dhcp_opt **dop, *ndop;
size_t *dop_len, dl;
struct vivco *vivco;
+ struct token *token;
#ifdef INET6
size_t sl;
struct if_ia *ia;
vivco->len = s;
vivco->data = (uint8_t *)np;
break;
+ case O_AUTHPROTOCOL:
+ fp = strwhite(arg);
+ if (fp)
+ *fp++ = '\0';
+ if (strcasecmp(arg, "token") == 0)
+ ifo->auth.protocol = AUTH_PROTO_TOKEN;
+ else if (strcasecmp(arg, "delayed") == 0)
+ ifo->auth.protocol = AUTH_PROTO_DELAYED;
+ else if (strcasecmp(arg, "delayedrealm") == 0)
+ ifo->auth.protocol = AUTH_PROTO_DELAYEDREALM;
+ else {
+ syslog(LOG_ERR, "%s: unsupported protocol", arg);
+ return -1;
+ }
+ arg = strskipwhite(fp);
+ fp = strwhite(arg);
+ if (arg == NULL) {
+ ifo->auth.options |= DHCPCD_AUTH_SEND;
+ ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
+ ifo->auth.rdm = AUTH_RDM_MONOTONIC;
+ break;
+ }
+ if (fp)
+ *fp++ = '\0';
+ if (strcasecmp(arg, "hmacmd5") == 0 ||
+ strcasecmp(arg, "hmac-md5") == 0)
+ ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
+ else {
+ syslog(LOG_ERR, "%s: unsupported algorithm", arg);
+ return 1;
+ }
+ arg = fp;
+ if (arg == NULL) {
+ ifo->auth.options |= DHCPCD_AUTH_SEND;
+ ifo->auth.rdm = AUTH_RDM_MONOTONIC;
+ break;
+ }
+ if (strcasecmp(arg, "monotonic") == 0)
+ ifo->auth.rdm = AUTH_RDM_MONOTONIC;
+ else {
+ syslog(LOG_ERR, "%s: unsupported RDM", arg);
+ return -1;
+ }
+ break;
+ case O_AUTHTOKEN:
+ fp = strwhite(arg);
+ if (fp == NULL) {
+ syslog(LOG_ERR, "authtoken requires a realm");
+ return -1;
+ }
+ *fp++ = '\0';
+ token = malloc(sizeof(*token));
+ if (token == NULL) {
+ syslog(LOG_ERR, "%s: %m", __func__);
+ return -1;
+ }
+ if (parse_uint32(&token->secretid, arg) == -1) {
+ syslog(LOG_ERR, "%s: not a number", arg);
+ free(token);
+ return -1;
+ }
+ arg = fp;
+ fp = strend(arg);
+ if (fp == NULL) {
+ syslog(LOG_ERR, "authtoken requies an a key");
+ free(token);
+ return -1;
+ }
+ *fp++ = '\0';
+ token->realm_len = parse_string(NULL, 0, arg);
+ if (token->realm_len) {
+ token->realm = malloc(token->realm_len);
+ if (token->realm == NULL) {
+ free(token);
+ syslog(LOG_ERR, "%s: %m", __func__);
+ return -1;
+ }
+ parse_string((char *)token->realm, token->realm_len,
+ arg);
+ }
+ arg = fp;
+ fp = strend(arg);
+ if (fp == NULL) {
+ syslog(LOG_ERR, "authtoken requies an an expiry date");
+ free(token->realm);
+ free(token);
+ return -1;
+ }
+ *fp++ = '\0';
+ if (*arg == '"') {
+ arg++;
+ np = strchr(arg, '"');
+ if (np)
+ *np = '\0';
+ }
+ if (strcmp(arg, "0") == 0 || strcasecmp(arg, "forever") == 0)
+ token->expire =0;
+ else {
+ struct tm tm;
+
+ memset(&tm, 0, sizeof(tm));
+ if (strptime(arg, "%Y-%m-%d %H:%M", &tm) == NULL) {
+ syslog(LOG_ERR, "%s: invalid date time", arg);
+ free(token->realm);
+ free(token);
+ return -1;
+ }
+ if ((token->expire = mktime(&tm)) == (time_t)-1) {
+ syslog(LOG_ERR, "%s: mktime: %m", __func__);
+ free(token->realm);
+ free(token);
+ return -1;
+ }
+ }
+ arg = fp;
+ token->key_len = parse_string(NULL, 0, arg);
+ if (token->key_len == 0) {
+ syslog(LOG_ERR, "authtoken needs a key");
+ free(token->realm);
+ free(token);
+ return -1;
+ }
+ token->key = malloc(token->key_len);
+ parse_string((char *)token->key, token->key_len, arg);
+ TAILQ_INSERT_TAIL(&ifo->auth.tokens, token, next);
+ break;
+ case O_AUTHNOTREQUIRED:
+ ifo->auth.options &= ~DHCPCD_AUTH_REQUIRE;
+ break;
default:
return 0;
}
ifo->timeout = DEFAULT_TIMEOUT;
ifo->reboot = DEFAULT_REBOOT;
ifo->metric = -1;
+ ifo->auth.options |= DHCPCD_AUTH_REQUIRE;
+ TAILQ_INIT(&ifo->auth.tokens);
strlcpy(ifo->script, SCRIPT, sizeof(ifo->script));
ifo->vendorclassid[0] = strlen(vendor);
size_t i;
struct dhcp_opt *opt;
struct vivco *vo;
+ struct token *token;
if (ifo) {
if (ifo->environ) {
#endif
free(ifo->ia);
+ while ((token = TAILQ_FIRST(&ifo->auth.tokens))) {
+ TAILQ_REMOVE(&ifo->auth.tokens, token, next);
+ if (token->realm_len)
+ free(token->realm);
+ free(token->key);
+ free(token);
+ }
free(ifo);
}
}
#include <limits.h>
#include <stdint.h>
+#include "auth.h"
+
/* Don't set any optional arguments here so we retain POSIX
* compatibility with getopt */
#define IF_OPTS "46bc:de:f:gh:i:kl:m:no:pqr:s:t:u:v:wxy:z:ABC:DEF:GHI:JKLO:Q:S:TUVW:X:Z:"
size_t vivco_len;
struct dhcp_opt *vivso_override;
size_t vivso_override_len;
+
+ struct auth auth;
};
extern unsigned long long options;
--- /dev/null
+include ../config.mk
+
+PROG= test
+SRCS= test.c
+SRCS+= test_hmac_md5.c hmac_md5.c ${MD5_SRC}
+
+CFLAGS?= -O2
+CSTD?= c99
+CFLAGS+= -std=${CSTD}
+
+CPPFLAGS+= -I../crypt
+
+.PATH: ../crypt
+
+VPATH= . ../crypt
+
+OBJS+= ${SRCS:.c=.o}
+
+.c.o:
+ ${CC} ${CFLAGS} ${CPPFLAGS} -c $< -o $@
+
+all: ${PROG}
+
+clean:
+ rm -f ${OBJS} ${PROG} ${PROG}.core ${CLEANFILES}
+
+.depend: ${SRCS} ${COMPAT_SRCS}
+ ${CC} ${CPPFLAGS} -MM ${SRCS} ${COMPAT_SRCS} > .depend
+
+depend: .depend
+
+${PROG}: ${DEPEND} ${OBJS}
+ ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LDADD}
--- /dev/null
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "test.h"
+
+int main(void)
+{
+ int r = 0;
+
+ if (test_hmac_md5())
+ r = -1;
+
+ return r;
+}
--- /dev/null
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef TEST_H
+
+int test_hmac_md5(void);
+
+#endif
--- /dev/null
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+
+#include "../crypt/crypt.h"
+#include "test.h"
+
+/* RFC2202 MD5 implementation */
+
+static void
+print_hmac(uint8_t *hmac)
+{
+ int i;
+
+ printf("digest = 0x");
+ for (i = 0; i < 16; i++)
+ printf("%02x", *hmac++);
+ printf("\n");
+}
+
+static void
+hmac_md5_test1(void)
+{
+ uint8_t hmac[16];
+ const uint8_t text[] = "Hi There";
+ uint8_t key[16];
+ int i;
+
+ printf ("HMAC MD5 Test 1:\t\t");
+ for (i = 0; i < 16; i++)
+ key[i] = 0x0b;
+ hmac_md5(text, 8, key, 16, hmac);
+ print_hmac(hmac);
+ printf("\t\texpected result:\t 0x9294727a3638bb1c13f48ef8158bfc9d\n");
+}
+
+static void
+hmac_md5_test2(void)
+{
+ uint8_t hmac[16];
+ const uint8_t text[] = "what do ya want for nothing?";
+ const uint8_t key[] = "Jefe";
+
+ printf("HMAC MD5 Test 2:\t\t");
+ hmac_md5(text, 28, key, 4, hmac);
+ print_hmac(hmac);
+ printf("\t\texpected result:\t 0x750c783e6ab0b503eaa863e10a5db738\n");
+}
+
+static void
+hmac_md5_test3(void)
+{
+ uint8_t hmac[16];
+ uint8_t text[50];
+ uint8_t key[16];
+ int i;
+
+ printf ("HMAC MD5 Test 3:\t\t");
+ for (i = 0; i < 50; i++)
+ text[i] = 0xdd;
+ for (i = 0; i < 16; i++)
+ key[i] = 0xaa;
+ hmac_md5(text, 50, key, 16, hmac);
+ print_hmac(hmac);
+ printf("\t\texpected result:\t 0x56be34521d144c88dbb8c733f0e8b3f6\n");
+}
+
+static void
+hmac_md5_test4(void)
+{
+ uint8_t hmac[16];
+ uint8_t text[50];
+ uint8_t key[25];
+ int i;
+
+ printf ("HMAC MD5 Test 4:\t\t");
+ for (i = 0; i < 50; i++)
+ text[i] = 0xcd;
+ for (i = 0; i < 25; i++)
+ key[i] = i + 1;
+ hmac_md5(text, 50, key, 25, hmac);
+ print_hmac(hmac);
+ printf("\t\texpected result:\t 0x697eaf0aca3a3aea3a75164746ffaa79\n");
+}
+
+static void
+hmac_md5_test5(void)
+{
+ uint8_t hmac[16];
+ const uint8_t text[] = "Test With Truncation";
+ uint8_t key[16];
+ int i;
+
+ printf ("HMAC MD5 Test 5:\t\t");
+ for (i = 0; i < 16; i++)
+ key[i] = 0x0c;
+ hmac_md5(text, 20, key, 16, hmac);
+ print_hmac(hmac);
+ printf("\t\texpected result:\t 0x56461ef2342edc00f9bab995690efd4c\n");
+}
+
+static void
+hmac_md5_test6(void)
+{
+ uint8_t hmac[16];
+ const uint8_t text[] = "Test Using Larger Than Block-Size Key - Hash Key First";
+ uint8_t key[80];
+ int i;
+
+ printf ("HMAC MD5 Test 6:\t\t");
+ for (i = 0; i < 80; i++)
+ key[i] = 0xaa;
+ hmac_md5(text, 54, key, 80, hmac);
+ print_hmac(hmac);
+ printf("\t\texpected result:\t 0x6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd\n");
+}
+
+static void
+hmac_md5_test7(void)
+{
+ uint8_t hmac[16];
+ const uint8_t text[] = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data";
+ uint8_t key[80];
+ int i;
+
+ printf ("HMAC MD5 Test 7:\t\t");
+ for (i = 0; i < 80; i++)
+ key[i] = 0xaa;
+ hmac_md5(text, 73, key, 80, hmac);
+ print_hmac(hmac);
+ printf("\t\texpected result:\t 0x6f630fad67cda0ee1fb1f562db3aa53e\n");
+}
+
+int test_hmac_md5(void)
+{
+
+ printf ("Starting HMAC MD5 tests...\n\n");
+ hmac_md5_test1();
+ hmac_md5_test2();
+ hmac_md5_test3();
+ hmac_md5_test4();
+ hmac_md5_test5();
+ hmac_md5_test6();
+ hmac_md5_test7();
+ printf("\nConfirm above results visually against RFC 2202.\n");
+ return 0;
+}