123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863 |
- /*
- * $Id: sendserver.c,v 1.30 2010/06/15 09:22:52 aland Exp $
- *
- * Copyright (C) 1995,1996,1997 Lars Fenneberg
- *
- * Copyright 1992 Livingston Enterprises, Inc.
- *
- * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
- * and Merit Network, Inc. All Rights Reserved
- *
- * See the file COPYRIGHT for the respective terms and conditions.
- * If the file is missing contact me at lf@elemental.net
- * and I'll send you a copy.
- *
- */
- //#include <poll.h>
- #include <radius_config.h>
- #include <includes.h>
- #include <freeradius-client.h>
- #include <pathnames.h>
- #include "util.h"
- #include "radius_user.h"
- #include "lwip/sockets.h"
- #define SA(p) ((struct sockaddr *)(p))
- static void rc_random_vector (unsigned char *);
- static int rc_check_reply (AUTH_HDR *, int, char const *, unsigned char const *, unsigned char);
- /** Packs an attribute value pair list into a buffer
- *
- * @param vp a pointer to a #VALUE_PAIR.
- * @param secret the secret used by the server.
- * @param auth a pointer to #AUTH_HDR.
- * @return The number of octets packed.
- */
- static int rc_pack_list (VALUE_PAIR *vp, char *secret, AUTH_HDR *auth)
- {
- int length, i, pc, padded_length;
- int total_length = 0;
- size_t secretlen;
- uint32_t lvalue, vendor;
- unsigned char passbuf[MAX(AUTH_PASS_LEN, CHAP_VALUE_LENGTH)];
- unsigned char md5buf[256];
- unsigned char *buf, *vector, *vsa_length_ptr;
- buf = auth->data;
- while (vp != NULL)
- {
- vsa_length_ptr = NULL;
- if (VENDOR(vp->attribute) != 0) {
- *buf++ = PW_VENDOR_SPECIFIC;
- vsa_length_ptr = buf;
- *buf++ = 6;
- vendor = htonl(VENDOR(vp->attribute));
- memcpy(buf, &vendor, sizeof(uint32_t));
- buf += 4;
- total_length += 6;
- }
- *buf++ = (vp->attribute & 0xff);
- switch (vp->attribute)
- {
- case PW_USER_PASSWORD:
- /* Encrypt the password */
- /* Chop off password at AUTH_PASS_LEN */
- length = vp->lvalue;
- if (length > AUTH_PASS_LEN)
- length = AUTH_PASS_LEN;
- /* Calculate the padded length */
- padded_length = (length+(AUTH_VECTOR_LEN-1)) & ~(AUTH_VECTOR_LEN-1);
- /* Record the attribute length */
- *buf++ = padded_length + 2;
- if (vsa_length_ptr != NULL) *vsa_length_ptr += padded_length + 2;
- /* Pad the password with zeros */
- memset ((char *) passbuf, '\0', AUTH_PASS_LEN);
- memcpy ((char *) passbuf, vp->strvalue, (size_t) length);
- secretlen = strlen (secret);
- vector = (unsigned char *)auth->vector;
- for(i = 0; i < padded_length; i += AUTH_VECTOR_LEN)
- {
- /* Calculate the MD5 digest*/
- strcpy ((char *) md5buf, secret);
- memcpy ((char *) md5buf + secretlen, vector,
- AUTH_VECTOR_LEN);
- rc_md5_calc (buf, md5buf, secretlen + AUTH_VECTOR_LEN);
- /* Remeber the start of the digest */
- vector = buf;
- /* Xor the password into the MD5 digest */
- for (pc = i; pc < (i + AUTH_VECTOR_LEN); pc++)
- {
- *buf++ ^= passbuf[pc];
- }
- }
- total_length += padded_length + 2;
- break;
- default:
- switch (vp->type)
- {
- case PW_TYPE_STRING:
- length = vp->lvalue;
- *buf++ = length + 2;
- if (vsa_length_ptr != NULL) *vsa_length_ptr += length + 2;
- memcpy (buf, vp->strvalue, (size_t) length);
- buf += length;
- total_length += length + 2;
- break;
- case PW_TYPE_IPV6ADDR:
- length = 16;
- *buf++ = length + 2;
- if (vsa_length_ptr != NULL) *vsa_length_ptr += length + 2;
- memcpy (buf, vp->strvalue, (size_t) length);
- buf += length;
- total_length += length + 2;
- break;
- case PW_TYPE_IPV6PREFIX:
- length = vp->lvalue;
- *buf++ = length + 2;
- if (vsa_length_ptr != NULL) *vsa_length_ptr += length + 2;
- memcpy (buf, vp->strvalue, (size_t) length);
- buf += length;
- total_length += length + 2;
- break;
- case PW_TYPE_INTEGER:
- case PW_TYPE_IPADDR:
- case PW_TYPE_DATE:
- *buf++ = sizeof (uint32_t) + 2;
- if (vsa_length_ptr != NULL) *vsa_length_ptr += sizeof(uint32_t) + 2;
- lvalue = htonl (vp->lvalue);
- memcpy (buf, (char *) &lvalue, sizeof (uint32_t));
- buf += sizeof (uint32_t);
- total_length += sizeof (uint32_t) + 2;
- break;
- default:
- break;
- }
- break;
- }
- vp = vp->next;
- }
- return total_length;
- }
- /** Appends a string to the provided buffer
- *
- * @param dest the destination buffer.
- * @param max_size the maximum size available in the destination buffer.
- * @param pos the current position in the dest buffer; initially must be zero.
- * @param src the source buffer to append.
- */
- static void strappend(char *dest, unsigned max_size, int *pos, const char *src)
- {
- unsigned len = strlen(src) + 1;
- if (*pos == -1)
- return;
- if (len + *pos > max_size) {
- *pos = -1;
- return;
- }
- memcpy(&dest[*pos], src, len);
- *pos += len-1;
- return;
- }
- /** Sends a request to a RADIUS server and waits for the reply
- *
- * @param rh a handle to parsed configuration
- * @param data a pointer to a #SEND_DATA structure
- * @param msg must be an array of %PW_MAX_MSG_SIZE or %NULL; will contain the concatenation of
- * any %PW_REPLY_MESSAGE received.
- * @param flags must be %AUTH or %ACCT
- * @return %OK_RC (0) on success, %TIMEOUT_RC on timeout %REJECT_RC on acess reject, or negative
- * on failure as return value.
- */
- #define RS_PORT_NUM 1812
- //#define RS_IP_ADDR "192.168.1.2"
- #define RS_IP_ADDR "192.168.14.234"
- #define DEVICE_PORT_NUM 1812
- //#define DEVICE_IP_ADDR "192.168.1.6"
- #define DEVICE_IP_ADDR "192.168.14.37"
- #define BUF_LEN 300
- static uint8_t send_buffer[BUF_LEN];
- static uint8_t recv_buffer[BUF_LEN];
- int rc_send_server (rc_handle *rh, SEND_DATA *data, char *msg, unsigned flags)
- {
- #if 1
- struct sockaddr_in sa,ra;
- int socket;
- fdsets sets;
- AUTH_HDR* auth;
- AUTH_HDR* recv_auth;
- unsigned char vector[AUTH_VECTOR_LEN];
- char secret[MAX_SECRET_LENGTH + 1];
- int total_length;
- int sendLen, recvLen;
- int length;
- int pos;
- uint8_t* attr;
- int result = 0;
- VALUE_PAIR* vp;
-
-
- initFdsets(&sets);
-
- if(data->secret != NULL) {
- strlcpy(secret, data->secret, MAX_SECRET_LENGTH);
- }
- memset(&ra, 0, sizeof(struct sockaddr_in));
- ra.sin_family = AF_INET;
- ra.sin_addr.s_addr = inet_addr(RS_IP_ADDR);
- ra.sin_port = htons(RS_PORT_NUM);
-
- socket = socket(PF_INET, SOCK_DGRAM, 0);
- if ( socket < 0 )
- {
- printf("socket call failed");
- return -1;
- }
-
- // TODO bind?
-
- // Build a request (PW_ACCESS_REQUEST)
- auth = (AUTH_HDR *) send_buffer;
- auth->code = data->code;
- auth->id = data->seq_nbr;
- rc_random_vector(vector);
- memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN);
- total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN;
- auth->length = htons ((unsigned short) total_length);
-
-
- // Bind socket
- memset(&sa, 0, sizeof(struct sockaddr_in));
- sa.sin_family = AF_INET;
- sa.sin_addr.s_addr = inet_addr(DEVICE_IP_ADDR);
- sa.sin_port = htons(DEVICE_PORT_NUM);
-
- if (bind(socket, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) == -1)
- {
- printf("Bind to Port Number %d ,IP address %s failed\n", DEVICE_PORT_NUM, DEVICE_IP_ADDR);
- close(socket);
- return 0;
- }
-
- sendLen = sendto(socket, (char*)auth, total_length, 0, (struct sockaddr*)&ra, sizeof(ra));
- if(sendLen < 0)
- {
- printf("send failed\n");
- close(socket);
- return 0;
- }
-
- // Получение ответа, select
- if (!recvSelect(&sets, &socket, 2000)) {
- //timeCount = HAL_GetTick() - timeCount;
- printf("SOCK recv timeout!\r\n");
- close(socket);
- return 0;
- }
-
- // Данные можно принимать
- socklen_t sl = sizeof(sa);
- recvLen = recvfrom(socket, recv_buffer, BUF_LEN, 0, (struct sockaddr*)&ra, &sl);
- recv_auth = (AUTH_HDR*)recv_buffer;
-
- // Проверки размера входящего сообщения
- if (recvLen < AUTH_HDR_LEN || recvLen < ntohs(recv_auth->length)) {
- printf("radius_server: reply is too short\r\n");
- close(socket);
- return 0;
- }
-
- if (recvLen > ntohs(recv_auth->length))
- {
- recvLen = ntohs(recv_auth->length);
- }
-
- // Verify that it's a valid RADIUS packet before doing ANYTHING with it.
- attr = recv_buffer + AUTH_HDR_LEN;
- while (attr < (recv_buffer + recvLen)) {
- if (attr[0] == 0) {
- printf("radius_server: attribute zero is invalid\r\n");
- close(socket);
- return 0;
- }
- if (attr[1] < 2) {
- printf("radius_server: attribute length is too small\r\n");
- close(socket);
- return 0;
- }
- if ((attr + attr[1]) > (recv_buffer + recvLen)) {
- printf("radius_server: attribute overflows the packet\r\n");
- close(socket);
- return 0;
- }
- attr += attr[1];
- }
-
-
- result = rc_check_reply (recv_auth, BUF_LEN, secret, vector, data->seq_nbr);
-
- length = ntohs(recv_auth->length) - AUTH_HDR_LEN;
- if (length > 0) {
- data->receive_pairs = rc_avpair_gen(rh, NULL, recv_auth->data, length, 0);
- } else {
- data->receive_pairs = NULL;
- }
- if (result != OK_RC) {
- return result;
- }
-
- if (msg) {
- *msg = '\0';
- pos = 0;
- vp = data->receive_pairs;
- while (vp)
- {
- if ((vp = rc_avpair_get(vp, PW_REPLY_MESSAGE, 0)))
- {
- strappend(msg, PW_MAX_MSG_SIZE, &pos, vp->strvalue);
- strappend(msg, PW_MAX_MSG_SIZE, &pos, "\n");
- vp = vp->next;
- }
- }
- }
- if ((recv_auth->code == PW_ACCESS_ACCEPT) ||
- (recv_auth->code == PW_PASSWORD_ACK) ||
- (recv_auth->code == PW_ACCOUNTING_RESPONSE))
- {
- result = OK_RC;
- }
- else if ((recv_auth->code == PW_ACCESS_REJECT) ||
- (recv_auth->code == PW_PASSWORD_REJECT))
- {
- result = REJECT_RC;
- }
- else
- {
- rc_log(LOG_ERR, "rc_send_server: received RADIUS server response neither ACCEPT nor REJECT, invalid");
- result = BADRESP_RC;
- }
-
-
-
-
- printf("Radius server end communication\r\n");
- close(socket);
- return result;
-
- //getnameinfo(SA(&our_sockaddr), SS_LEN(&our_sockaddr), NULL, 0, our_addr_txt, sizeof(our_addr_txt), NI_NUMERICHOST);
- //getnameinfo(auth_addr->ai_addr, auth_addr->ai_addrlen, NULL, 0, auth_addr_txt, sizeof(auth_addr_txt), NI_NUMERICHOST);
-
- #endif
-
- #if 0
- int sockfd;
- AUTH_HDR *auth, *recv_auth;
- char *server_name; /* Name of server to query */
- struct sockaddr_storage our_sockaddr;
- struct addrinfo *auth_addr = NULL;
- socklen_t salen;
- int result = 0;
- int total_length;
- int length, pos;
- int retry_max;
- unsigned discover_local_ip;
- size_t secretlen;
- char secret[MAX_SECRET_LENGTH + 1];
- unsigned char vector[AUTH_VECTOR_LEN];
- uint8_t recv_buffer[BUFFER_LEN];
- uint8_t send_buffer[BUFFER_LEN];
- char our_addr_txt[50]; /* hold a text IP */
- char auth_addr_txt[50]; /* hold a text IP */
- uint8_t *attr;
- int retries;
- VALUE_PAIR *vp;
- //struct pollfd pfd;
- double start_time, timeout;
-
- server_name = data->server;
- if (server_name == NULL || server_name[0] == '\0')
- return ERROR_RC;
- if(data->secret != NULL)
- {
- //strlcpy(secret, data->secret, MAX_SECRET_LENGTH);
- memcpy(secret, data->secret, MAX_SECRET_LENGTH);
- }
-
- if (rc_find_server_addr (rh, server_name, &auth_addr, secret, flags) != 0)
- {
- rc_log(LOG_ERR, "rc_send_server: unable to find server: %s", server_name);
- return ERROR_RC;
- }
- rc_own_bind_addr(rh, &our_sockaddr);
- discover_local_ip = 0;
- if (our_sockaddr.ss_family == AF_INET) {
- if (((struct sockaddr_in*)(&our_sockaddr))->sin_addr.s_addr == INADDR_ANY) {
- discover_local_ip = 1;
- }
- }
- DEBUG(LOG_ERR, "DEBUG: rc_send_server: creating socket to: %s", server_name);
- if (discover_local_ip) {
- result = rc_get_srcaddr(SA(&our_sockaddr), auth_addr->ai_addr);
- if (result != 0) {
- memset (secret, '\0', sizeof (secret));
- rc_log(LOG_ERR, "rc_send_server: cannot figure our own address");
- result = ERROR_RC;
- goto cleanup;
- }
- }
- sockfd = socket (our_sockaddr.ss_family, SOCK_DGRAM, 0);
- if (sockfd < 0)
- {
- memset (secret, '\0', sizeof (secret));
- rc_log(LOG_ERR, "rc_send_server: socket: %s", strerror(errno));
- result = ERROR_RC;
- goto cleanup;
- }
- if (our_sockaddr.ss_family == AF_INET)
- ((struct sockaddr_in*)&our_sockaddr)->sin_port = 0;
- else
- ((struct sockaddr_in6*)&our_sockaddr)->sin6_port = 0;
- if (bind(sockfd, SA(&our_sockaddr), SS_LEN(&our_sockaddr)) < 0)
- {
- close (sockfd);
- memset (secret, '\0', sizeof (secret));
- rc_log(LOG_ERR, "rc_send_server: bind: %s: %s", server_name, strerror(errno));
- result = ERROR_RC;
- goto cleanup;
- }
- retry_max = data->retries; /* Max. numbers to try for reply */
- retries = 0; /* Init retry cnt for blocking call */
- if (data->svc_port) {
- if (our_sockaddr.ss_family == AF_INET)
- ((struct sockaddr_in*)auth_addr->ai_addr)->sin_port = htons ((unsigned short) data->svc_port);
- else
- ((struct sockaddr_in6*)auth_addr->ai_addr)->sin6_port = htons ((unsigned short) data->svc_port);
- }
- /*
- * Fill in NAS-IP-Address (if needed)
- */
- if (rc_avpair_get(data->send_pairs, PW_NAS_IP_ADDRESS, 0) == NULL &&
- rc_avpair_get(data->send_pairs, PW_NAS_IPV6_ADDRESS, 0) == NULL) {
- if (our_sockaddr.ss_family == AF_INET) {
- uint32_t ip;
- ip = *((uint32_t*)(&((struct sockaddr_in*)&our_sockaddr)->sin_addr));
- ip = ntohl(ip);
- rc_avpair_add(rh, &(data->send_pairs), PW_NAS_IP_ADDRESS,
- &ip, 0, 0);
- } else {
- void *p;
- p = &((struct sockaddr_in6*)&our_sockaddr)->sin6_addr;
- rc_avpair_add(rh, &(data->send_pairs), PW_NAS_IPV6_ADDRESS,
- p, 0, 0);
- }
- }
- /* Build a request */
- auth = (AUTH_HDR *) send_buffer;
- auth->code = data->code;
- auth->id = data->seq_nbr;
- if (data->code == PW_ACCOUNTING_REQUEST)
- {
- total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN;
- auth->length = htons ((unsigned short) total_length);
- memset((char *) auth->vector, 0, AUTH_VECTOR_LEN);
- secretlen = strlen (secret);
- memcpy ((char *) auth + total_length, secret, secretlen);
- rc_md5_calc (vector, (unsigned char *) auth, total_length + secretlen);
- memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN);
- }
- else
- {
- rc_random_vector (vector);
- memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN);
- total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN;
- auth->length = htons ((unsigned short) total_length);
- }
- getnameinfo(SA(&our_sockaddr), SS_LEN(&our_sockaddr), NULL, 0, our_addr_txt, sizeof(our_addr_txt), NI_NUMERICHOST);
- getnameinfo(auth_addr->ai_addr, auth_addr->ai_addrlen, NULL, 0, auth_addr_txt, sizeof(auth_addr_txt), NI_NUMERICHOST);
- DEBUG(LOG_ERR, "DEBUG: local %s : 0, remote %s : %u\n",
- our_addr_txt, auth_addr_txt, data->svc_port);
- for (;;)
- {
- do {
- result = sendto (sockfd, (char *) auth, (unsigned int)total_length,
- (int) 0, SA(auth_addr->ai_addr), auth_addr->ai_addrlen);
- } while (result == -1 && errno == EINTR);
- if (result == -1) {
- rc_log(LOG_ERR, "%s: socket: %s", __FUNCTION__, strerror(errno));
- }
- pfd.fd = sockfd;
- pfd.events = POLLIN;
- pfd.revents = 0;
- start_time = rc_getctime();
- for (timeout = data->timeout; timeout > 0;
- timeout -= rc_getctime() - start_time) {
- result = poll(&pfd, 1, timeout * 1000);
- if (result != -1 || errno != EINTR)
- break;
- }
- if (result == -1)
- {
- rc_log(LOG_ERR, "rc_send_server: poll: %s", strerror(errno));
- memset (secret, '\0', sizeof (secret));
- close (sockfd);
- result = ERROR_RC;
- goto cleanup;
- }
- if (result == 1 && (pfd.revents & POLLIN) != 0)
- break;
- /*
- * Timed out waiting for response. Retry "retry_max" times
- * before giving up. If retry_max = 0, don't retry at all.
- */
- if (retries++ >= retry_max)
- {
- rc_log(LOG_ERR,
- "rc_send_server: no reply from RADIUS server %s:%u",
- auth_addr_txt, data->svc_port);
- close (sockfd);
- memset (secret, '\0', sizeof (secret));
- result = TIMEOUT_RC;
- goto cleanup;
- }
- }
- salen = auth_addr->ai_addrlen;
- do {
- length = recvfrom (sockfd, (char *) recv_buffer,
- (int) sizeof (recv_buffer),
- (int) 0, SA(auth_addr->ai_addr), &salen);
- } while(length == -1 && errno == EINTR);
- if (length <= 0)
- {
- rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: %s", server_name,\
- data->svc_port, strerror(errno));
- close (sockfd);
- memset (secret, '\0', sizeof (secret));
- result = ERROR_RC;
- goto cleanup;
- }
- recv_auth = (AUTH_HDR *)recv_buffer;
- if (length < AUTH_HDR_LEN || length < ntohs(recv_auth->length)) {
- rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: reply is too short",
- server_name, data->svc_port);
- close(sockfd);
- memset(secret, '\0', sizeof(secret));
- result = ERROR_RC;
- goto cleanup;
- }
- /*
- * If UDP is larger than RADIUS, shorten it to RADIUS.
- */
- if (length > ntohs(recv_auth->length)) length = ntohs(recv_auth->length);
- /*
- * Verify that it's a valid RADIUS packet before doing ANYTHING with it.
- */
- attr = recv_buffer + AUTH_HDR_LEN;
- while (attr < (recv_buffer + length)) {
- if (attr[0] == 0) {
- rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: attribute zero is invalid",
- server_name, data->svc_port);
- close(sockfd);
- memset(secret, '\0', sizeof(secret));
- return ERROR_RC;
- }
- if (attr[1] < 2) {
- rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: attribute length is too small",
- server_name, data->svc_port);
- close(sockfd);
- memset(secret, '\0', sizeof(secret));
- return ERROR_RC;
- }
- if ((attr + attr[1]) > (recv_buffer + length)) {
- rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: attribute overflows the packet",
- server_name, data->svc_port);
- close(sockfd);
- memset(secret, '\0', sizeof(secret));
- return ERROR_RC;
- }
- attr += attr[1];
- }
- result = rc_check_reply (recv_auth, BUFFER_LEN, secret, vector, data->seq_nbr);
- length = ntohs(recv_auth->length) - AUTH_HDR_LEN;
- if (length > 0) {
- data->receive_pairs = rc_avpair_gen(rh, NULL, recv_auth->data,
- length, 0);
- } else {
- data->receive_pairs = NULL;
- }
- close (sockfd);
- memset (secret, '\0', sizeof (secret));
- if (result != OK_RC) {
- goto cleanup;
- }
- if (msg) {
- *msg = '\0';
- pos = 0;
- vp = data->receive_pairs;
- while (vp)
- {
- if ((vp = rc_avpair_get(vp, PW_REPLY_MESSAGE, 0)))
- {
- strappend(msg, PW_MAX_MSG_SIZE, &pos, vp->strvalue);
- strappend(msg, PW_MAX_MSG_SIZE, &pos, "\n");
- vp = vp->next;
- }
- }
- }
- if ((recv_auth->code == PW_ACCESS_ACCEPT) ||
- (recv_auth->code == PW_PASSWORD_ACK) ||
- (recv_auth->code == PW_ACCOUNTING_RESPONSE))
- {
- result = OK_RC;
- }
- else if ((recv_auth->code == PW_ACCESS_REJECT) ||
- (recv_auth->code == PW_PASSWORD_REJECT))
- {
- result = REJECT_RC;
- }
- else
- {
- rc_log(LOG_ERR, "rc_send_server: received RADIUS server response neither ACCEPT nor REJECT, invalid");
- result = BADRESP_RC;
- }
- cleanup:
- if (auth_addr)
- freeaddrinfo(auth_addr);
- return result;
- #endif
- }
- /** Verify items in returned packet
- *
- * @param auth a pointer to #AUTH_HDR.
- * @param bufferlen the available buffer length.
- * @param secret the secret used by the server.
- * @param vector a random vector of %AUTH_VECTOR_LEN.
- * @param seq_nbr a unique sequence number.
- * @return %OK_RC upon success, %BADRESP_RC if anything looks funny.
- */
- static int rc_check_reply (AUTH_HDR *auth, int bufferlen, char const *secret, unsigned char const *vector, uint8_t seq_nbr)
- {
- int secretlen;
- int totallen;
- unsigned char calc_digest[AUTH_VECTOR_LEN];
- unsigned char reply_digest[AUTH_VECTOR_LEN];
- #ifdef DIGEST_DEBUG
- uint8_t *ptr;
- #endif
- totallen = ntohs (auth->length);
- secretlen = (int)strlen (secret);
- /* Do sanity checks on packet length */
- if ((totallen < 20) || (totallen > 4096))
- {
- rc_log(LOG_ERR, "rc_check_reply: received RADIUS server response with invalid length");
- return BADRESP_RC;
- }
- /* Verify buffer space, should never trigger with current buffer size and check above */
- if ((totallen + secretlen) > bufferlen)
- {
- rc_log(LOG_ERR, "rc_check_reply: not enough buffer space to verify RADIUS server response");
- return BADRESP_RC;
- }
- /* Verify that id (seq. number) matches what we sent */
- if (auth->id != seq_nbr)
- {
- rc_log(LOG_ERR, "rc_check_reply: received non-matching id in RADIUS server response");
- return BADRESP_RC;
- }
- /* Verify the reply digest */
- memcpy ((char *) reply_digest, (char *) auth->vector, AUTH_VECTOR_LEN);
- memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN);
- memcpy ((char *) auth + totallen, secret, secretlen);
- #ifdef DIGEST_DEBUG
- rc_log(LOG_ERR, "Calculating digest on:");
- for (ptr = (u_char *)auth; ptr < ((u_char *)auth) + totallen + secretlen; ptr += 32) {
- char buf[65];
- int i;
- buf[0] = '\0';
- for (i = 0; i < 32; i++) {
- if (ptr + i >= ((u_char *)auth) + totallen + secretlen)
- break;
- sprintf(buf + i * 2, "%.2X", ptr[i]);
- }
- rc_log(LOG_ERR, " %s", buf);
- }
- #endif
- rc_md5_calc (calc_digest, (unsigned char *) auth, totallen + secretlen);
- #ifdef DIGEST_DEBUG
- rc_log(LOG_ERR, "Calculated digest is:");
- for (ptr = (u_char *)calc_digest; ptr < ((u_char *)calc_digest) + 16; ptr += 32) {
- char buf[65];
- int i;
- buf[0] = '\0';
- for (i = 0; i < 32; i++) {
- if (ptr + i >= ((u_char *)calc_digest) + 16)
- break;
- sprintf(buf + i * 2, "%.2X", ptr[i]);
- }
- rc_log(LOG_ERR, " %s", buf);
- }
- rc_log(LOG_ERR, "Reply digest is:");
- for (ptr = (u_char *)reply_digest; ptr < ((u_char *)reply_digest) + 16; ptr += 32) {
- char buf[65];
- int i;
- buf[0] = '\0';
- for (i = 0; i < 32; i++) {
- if (ptr + i >= ((u_char *)reply_digest) + 16)
- break;
- sprintf(buf + i * 2, "%.2X", ptr[i]);
- }
- rc_log(LOG_ERR, " %s", buf);
- }
- #endif
- if (memcmp ((char *) reply_digest, (char *) calc_digest,
- AUTH_VECTOR_LEN) != 0)
- {
- rc_log(LOG_ERR, "rc_check_reply: received invalid reply digest from RADIUS server");
- return BADRESP_RC;
- }
- return OK_RC;
- }
- /** Generates a random vector of AUTH_VECTOR_LEN octets
- *
- * @param vector a buffer with at least %AUTH_VECTOR_LEN bytes.
- */
- static void rc_random_vector (unsigned char *vector)
- {
- int randno;
- int i;
- #if defined(HAVE_GETENTROPY)
- if (getentropy(vector, AUTH_VECTOR_LEN) >= 0) {
- return;
- } /* else fall through */
- #elif defined(HAVE_DEV_URANDOM)
- int fd;
- /* well, I added this to increase the security for user passwords.
- we use /dev/urandom here, as /dev/random might block and we don't
- need that much randomness. BTW, great idea, Ted! -lf, 03/18/95 */
- if ((fd = open(_PATH_DEV_URANDOM, O_RDONLY)) >= 0)
- {
- unsigned char *pos;
- int readcount;
- i = AUTH_VECTOR_LEN;
- pos = vector;
- while (i > 0)
- {
- readcount = read(fd, (char *)pos, i);
- if (readcount >= 0) {
- pos += readcount;
- i -= readcount;
- } else {
- if (errno != EINTR && errno != EAGAIN)
- goto fallback;
- }
- }
- close(fd);
- return;
- } /* else fall through */
- #endif
- fallback:
- for (i = 0; i < AUTH_VECTOR_LEN;)
- {
- randno = random ();
- memcpy ((char *) vector, (char *) &randno, sizeof (int));
- vector += sizeof (int);
- i += sizeof (int);
- }
- return;
- }
|