-/*
- * Copyright (C) 2006-2008 Stig Venaas <venaas@uninett.no>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- */
+/* Copyright (c) 2007-2009, UNINETT AS */
+/* See LICENSE for licensing information. */
+#ifdef SYS_SOLARIS9
+#include <sys/inttypes.h>
+#else
#include <stdint.h>
+#endif
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
struct radmsg *radmsg_init(uint8_t code, uint8_t id, uint8_t *auth) {
struct radmsg *msg;
-
+
msg = malloc(sizeof(struct radmsg));
if (!msg)
return NULL;
if (!msg->attrs) {
free(msg);
return NULL;
- }
+ }
msg->code = code;
msg->id = id;
if (auth)
else if (!RAND_bytes(msg->auth, 16)) {
free(msg);
return NULL;
- }
+ }
return msg;
}
return list_push(msg->attrs, attr);
}
+/** Return a new list with all tlv's in \a msg of type \a type. The
+ * caller is responsible for freeing the list by calling \a
+ * list_free(). */
+struct list *
+radmsg_getalltype(const struct radmsg *msg, uint8_t type)
+{
+ struct list *list = NULL;
+ struct list_node *node = NULL;
+
+ if (!msg || !msg->attrs)
+ return NULL;
+ list = list_create();
+ if (!list)
+ return NULL;
+
+ for (node = list_first(msg->attrs); node; node = list_next(node))
+ if (((struct tlv *) node->data)->t == type)
+ if (list_push(list, node->data) != 1) {
+ list_free(list);
+ return NULL;
+ }
+ return list;
+}
+
/* returns first tlv of the given type */
struct tlv *radmsg_gettype(struct radmsg *msg, uint8_t type) {
struct list_node *node;
return NULL;
}
+/** Copy all attributes of type \a type from \a src to \a dst.
+ *
+ * If all attributes were copied successfully, the number of
+ * attributes copied is returned.
+ *
+ * If copying failed, a negative number is returned. The number
+ * returned is 0 minus the number of attributes successfully copied
+ * before the failure. */
+int radmsg_copy_attrs(struct radmsg *dst,
+ const struct radmsg *src,
+ uint8_t type)
+{
+ struct list_node *node = NULL;
+ struct list *list = radmsg_getalltype(src, type);
+ int n = 0;
+
+ for (node = list_first(list); node; node = list_next(node)) {
+ if (radmsg_add(dst, (struct tlv *) node->data) != 1) {
+ n = -n;
+ break;
+ }
+ n++;
+ }
+ list_free(list);
+ return n;
+}
+
int _checkmsgauth(unsigned char *rad, uint8_t *authattr, uint8_t *secret) {
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static unsigned char first = 1;
static HMAC_CTX hmacctx;
unsigned int md_len;
uint8_t auth[16], hash[EVP_MAX_MD_SIZE];
-
+
pthread_mutex_lock(&lock);
if (first) {
HMAC_CTX_init(&hmacctx);
debug(DBG_WARN, "message authenticator, wrong value");
pthread_mutex_unlock(&lock);
return 0;
- }
-
+ }
+
pthread_mutex_unlock(&lock);
return 1;
}
unsigned char hash[EVP_MAX_MD_SIZE];
unsigned int len;
int result;
-
+
pthread_mutex_lock(&lock);
if (first) {
EVP_MD_CTX_init(&mdctx);
}
len = RADLEN(rad);
-
+
result = (EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) &&
EVP_DigestUpdate(&mdctx, rad, 4) &&
EVP_DigestUpdate(&mdctx, reqauth, 16) &&
if (!authattrval)
return 1;
-
+
pthread_mutex_lock(&lock);
if (first) {
HMAC_CTX_init(&hmacctx);
return 1;
}
+int _radsign(unsigned char *rad, unsigned char *sec) {
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+ static unsigned char first = 1;
+ static EVP_MD_CTX mdctx;
+ unsigned int md_len;
+ int result;
+
+ pthread_mutex_lock(&lock);
+ if (first) {
+ EVP_MD_CTX_init(&mdctx);
+ first = 0;
+ }
+
+ result = (EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) &&
+ EVP_DigestUpdate(&mdctx, rad, RADLEN(rad)) &&
+ EVP_DigestUpdate(&mdctx, sec, strlen((char *)sec)) &&
+ EVP_DigestFinal_ex(&mdctx, rad + 4, &md_len) &&
+ md_len == 16);
+ pthread_mutex_unlock(&lock);
+ return result;
+}
+
uint8_t *radmsg2buf(struct radmsg *msg, uint8_t *secret) {
struct list_node *node;
struct tlv *tlv;
buf = malloc(size);
if (!buf)
return NULL;
-
+
p = buf;
*p++ = msg->code;
*p++ = msg->id;
free(buf);
return NULL;
}
+ if (secret) {
+ if ((msg->code == RAD_Access_Accept || msg->code == RAD_Access_Reject || msg->code == RAD_Access_Challenge || msg->code == RAD_Accounting_Response || msg->code == RAD_Accounting_Request) && !_radsign(buf, secret)) {
+ free(buf);
+ return NULL;
+ }
+ if (msg->code == RAD_Accounting_Request)
+ memcpy(msg->auth, buf + 4, 16);
+ }
return buf;
}
/* if secret set we also validate message authenticator if present */
struct radmsg *buf2radmsg(uint8_t *buf, uint8_t *secret, uint8_t *rqauth) {
struct radmsg *msg;
- uint8_t t, l, *v, *p, auth[16];
+ uint8_t t, l, *v = NULL, *p, auth[16];
uint16_t len;
struct tlv *attr;
-
+
len = RADLEN(buf);
if (len < 20)
return NULL;
debug(DBG_WARN, "buf2radmsg: Invalid auth, ignoring reply");
return NULL;
}
-
+
msg = radmsg_init(buf[0], buf[1], (uint8_t *)buf + 4);
if (!msg)
return NULL;
v = p;
p += l;
}
-
+
if (t == RAD_Attr_Message_Authenticator && secret) {
if (rqauth)
memcpy(buf + 4, rqauth, 16);
}
return msg;
}
+
+/* Local Variables: */
+/* c-file-style: "stroustrup" */
+/* End: */