X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=radmsg.c;h=7f6dd9dd305b1ac0bf61c7e0f8f5cc4d2b8559d1;hb=refs%2Fheads%2Fmaint-1.6;hp=26f8fbe7e8f11c41c6c6709dd242e4fc3f477ba4;hpb=faf8717dcbc9c2e3ed1892402133b6c9663a5e7d;p=radsecproxy.git diff --git a/radmsg.c b/radmsg.c index 26f8fbe..7f6dd9d 100644 --- a/radmsg.c +++ b/radmsg.c @@ -6,7 +6,11 @@ * copyright notice and this permission notice appear in all copies. */ +#ifdef SYS_SOLARIS9 +#include +#else #include +#endif #include #include #include @@ -16,6 +20,7 @@ #include "debug.h" #include #include +#include #define RADLEN(x) ntohs(((uint16_t *)(x))[1]) @@ -28,18 +33,24 @@ void radmsg_free(struct radmsg *msg) { 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; + memset(msg, 0, sizeof(struct radmsg)); msg->attrs = list_create(); if (!msg->attrs) { free(msg); return NULL; - } + } msg->code = code; msg->id = id; - memcpy(msg->auth, auth, 16); + if (auth) + memcpy(msg->auth, auth, 16); + else if (!RAND_bytes(msg->auth, 16)) { + free(msg); + return NULL; + } return msg; } @@ -51,6 +62,30 @@ int radmsg_add(struct radmsg *msg, struct tlv *attr) { 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; @@ -66,38 +101,29 @@ struct tlv *radmsg_gettype(struct radmsg *msg, uint8_t type) { return NULL; } -uint8_t *radmsg2buf(struct radmsg *msg) { - struct list_node *node; - struct tlv *tlv; - int size; - uint8_t *buf, *p; - - if (!msg || !msg->attrs) - return NULL; - size = 20; - for (node = list_first(msg->attrs); node; node = list_next(node)) - size += 2 + ((struct tlv *)node->data)->l; - if (size > 65535) - return NULL; - buf = malloc(size); - if (!buf) - return NULL; - - p = buf; - *p++ = msg->code; - *p++ = msg->id; - *(uint16_t *)p = htons(size); - p += 2; - memcpy(p, msg->auth, 16); - p += 16; +/** 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. */ +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(msg->attrs); node; node = list_next(node)) { - tlv = (struct tlv *)node->data; - p = tlv2buf(p, tlv); - p[-1] += 2; - p += tlv->l; + for (node = list_first(list); node; node = list_next(node)) { + if (radmsg_add(dst, copytlv((struct tlv *) node->data)) != 1) { + n = -1; + break; + } + n++; } - return buf; + list_free(list); + return n; } int _checkmsgauth(unsigned char *rad, uint8_t *authattr, uint8_t *secret) { @@ -106,7 +132,7 @@ int _checkmsgauth(unsigned char *rad, uint8_t *authattr, uint8_t *secret) { 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); @@ -130,8 +156,8 @@ int _checkmsgauth(unsigned char *rad, uint8_t *authattr, uint8_t *secret) { debug(DBG_WARN, "message authenticator, wrong value"); pthread_mutex_unlock(&lock); return 0; - } - + } + pthread_mutex_unlock(&lock); return 1; } @@ -143,7 +169,7 @@ int _validauth(unsigned char *rad, unsigned char *reqauth, unsigned char *sec) { unsigned char hash[EVP_MAX_MD_SIZE]; unsigned int len; int result; - + pthread_mutex_lock(&lock); if (first) { EVP_MD_CTX_init(&mdctx); @@ -151,7 +177,7 @@ int _validauth(unsigned char *rad, unsigned char *reqauth, unsigned char *sec) { } len = RADLEN(rad); - + result = (EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) && EVP_DigestUpdate(&mdctx, rad, 4) && EVP_DigestUpdate(&mdctx, reqauth, 16) && @@ -163,14 +189,113 @@ int _validauth(unsigned char *rad, unsigned char *reqauth, unsigned char *sec) { pthread_mutex_unlock(&lock); return result; } - + +int _createmessageauth(unsigned char *rad, unsigned char *authattrval, uint8_t *secret) { + static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + static unsigned char first = 1; + static HMAC_CTX hmacctx; + unsigned int md_len; + + if (!authattrval) + return 1; + + pthread_mutex_lock(&lock); + if (first) { + HMAC_CTX_init(&hmacctx); + first = 0; + } + + memset(authattrval, 0, 16); + md_len = 0; + HMAC_Init_ex(&hmacctx, secret, strlen((char *)secret), EVP_md5(), NULL); + HMAC_Update(&hmacctx, rad, RADLEN(rad)); + HMAC_Final(&hmacctx, authattrval, &md_len); + if (md_len != 16) { + debug(DBG_WARN, "message auth computation failed"); + pthread_mutex_unlock(&lock); + return 0; + } + pthread_mutex_unlock(&lock); + 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; + int size; + uint8_t *buf, *p, *msgauth = NULL; + + if (!msg || !msg->attrs) + return NULL; + size = 20; + for (node = list_first(msg->attrs); node; node = list_next(node)) + size += 2 + ((struct tlv *)node->data)->l; + if (size > 65535) + return NULL; + buf = malloc(size); + if (!buf) + return NULL; + + p = buf; + *p++ = msg->code; + *p++ = msg->id; + *(uint16_t *)p = htons(size); + p += 2; + memcpy(p, msg->auth, 16); + p += 16; + + for (node = list_first(msg->attrs); node; node = list_next(node)) { + tlv = (struct tlv *)node->data; + p = tlv2buf(p, tlv); + p[-1] += 2; + if (tlv->t == RAD_Attr_Message_Authenticator && secret) + msgauth = p; + p += tlv->l; + } + if (msgauth && !_createmessageauth(buf, msgauth, secret)) { + 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; @@ -187,7 +312,7 @@ struct radmsg *buf2radmsg(uint8_t *buf, uint8_t *secret, uint8_t *rqauth) { 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; @@ -211,7 +336,7 @@ struct radmsg *buf2radmsg(uint8_t *buf, uint8_t *secret, uint8_t *rqauth) { v = p; p += l; } - + if (t == RAD_Attr_Message_Authenticator && secret) { if (rqauth) memcpy(buf + 4, rqauth, 16); @@ -236,3 +361,7 @@ struct radmsg *buf2radmsg(uint8_t *buf, uint8_t *secret, uint8_t *rqauth) { } return msg; } + +/* Local Variables: */ +/* c-file-style: "stroustrup" */ +/* End: */