diff options
Diffstat (limited to 'accel-pppd/radius/req.c')
| -rw-r--r-- | accel-pppd/radius/req.c | 71 |
1 files changed, 63 insertions, 8 deletions
diff --git a/accel-pppd/radius/req.c b/accel-pppd/radius/req.c index 72c46b16..9a957493 100644 --- a/accel-pppd/radius/req.c +++ b/accel-pppd/radius/req.c @@ -5,6 +5,8 @@ #include <fcntl.h> #include <unistd.h> #include <assert.h> +#include <openssl/md5.h> +#include <openssl/crypto.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> @@ -17,6 +19,49 @@ #define HMAC_MD5_LEN 16 +/* Keep the signing secret and authenticator with the packet across reloads. */ +static int rad_req_set_RA(struct rad_req_t *req) +{ + char *secret = rad_server_secret_dup(req->serv); + MD5_CTX ctx; + + if (!secret) + return -1; + + memset(req->RA, 0, sizeof(req->RA)); + if (rad_packet_build(req->pack, req->RA)) { + _free(secret); + return -1; + } + + MD5_Init(&ctx); + MD5_Update(&ctx, req->pack->buf, req->pack->len); + MD5_Update(&ctx, secret, strlen(secret)); + MD5_Final(req->pack->buf + 4, &ctx); + memcpy(req->RA, req->pack->buf + 4, sizeof(req->RA)); + _free(req->pack->secret); + req->pack->secret = (uint8_t *)secret; + return 0; +} + +static int verify_response_authenticator(struct rad_req_t *req, struct rad_packet_t *pack) +{ + uint8_t expected[MD5_DIGEST_LENGTH]; + MD5_CTX ctx; + + if (!pack || !pack->buf || pack->len < 20 || + !req->pack->buf || !req->pack->secret) + return -1; + + MD5_Init(&ctx); + MD5_Update(&ctx, pack->buf, 4); + MD5_Update(&ctx, req->pack->buf + 4, 16); + MD5_Update(&ctx, pack->buf + 20, pack->len - 20); + MD5_Update(&ctx, req->pack->secret, strlen((char *)req->pack->secret)); + MD5_Final(expected, &ctx); + return CRYPTO_memcmp(expected, pack->buf + 4, sizeof(expected)); +} + static int make_socket(struct rad_req_t *req); static mempool_t req_pool; @@ -75,12 +120,15 @@ static struct rad_req_t *__rad_req_alloc(struct radius_pd_t *rpd, int code, cons if (!req->pack) goto out_err; - if (code == CODE_ACCESS_REQUEST && conf_blast_protection) { - uint8_t buf[HMAC_MD5_LEN] = {0}; - req->pack->message_authenticator = 1; + if (code == CODE_ACCESS_REQUEST) { req->pack->secret = (uint8_t *)rad_server_secret_dup(req->serv); if (!req->pack->secret) goto out_err; + } + + if (code == CODE_ACCESS_REQUEST && conf_blast_protection) { + uint8_t buf[HMAC_MD5_LEN] = {0}; + req->pack->message_authenticator = 1; if (rad_packet_add_octets(req->pack, NULL, "Message-Authenticator", buf, HMAC_MD5_LEN)) { _free(req->pack->secret); req->pack->secret = NULL; @@ -380,6 +428,10 @@ int __rad_req_send(struct rad_req_t *req, int async) if (req->before_send && req->before_send(req)) goto out_err; + /* Re-sign accounting after server selection, including retries without delay-time. */ + if (req->pack->code == CODE_ACCOUNTING_REQUEST && rad_req_set_RA(req)) + goto out_err; + if (!req->pack->buf && rad_packet_build(req->pack, req->RA)) goto out_err; @@ -461,12 +513,15 @@ int rad_req_read(struct triton_md_handler_t *h) if (rad_packet_recv(h->fd, &pack, NULL)) return 0; - rad_server_reply(req->serv); - - if (pack->id == req->pack->id) - break; + if (!pack) + return 0; + if (pack->id != req->pack->id || verify_response_authenticator(req, pack)) { + rad_packet_free(pack); + continue; + } - rad_packet_free(pack); + rad_server_reply(req->serv); + break; } req->reply = pack; |
