/** Builds an authentication/accounting request for port id client_port with the value_pairs send and submits it to a server * * @param rh a handle to parsed configuration. * @param client_port the client port number to use (may be zero to use any available). * @param send a #VALUE_PAIR array of values (e.g., %PW_USER_NAME). * @param received an allocated array of received values. * @param msg must be an array of %PW_MAX_MSG_SIZE or %NULL; will contain the concatenation of any * %PW_REPLY_MESSAGE received. * @param add_nas_port if non-zero it will include %PW_NAS_PORT in sent pairs. * @param request_type one of standard RADIUS codes (e.g., %PW_ACCESS_REQUEST). * @return received value_pairs in received, messages from the server in msg and %OK_RC (0) on success, negative * on failure as return value. */ int rc_aaa(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received, char *msg, int add_nas_port, int request_type) { SEND_DATA data; VALUE_PAIR *adt_vp = NULL; int result; int i, skip_count; SERVER *aaaserver; int timeout = rc_conf_int(rh, "radius_timeout"); int retries = rc_conf_int(rh, "radius_retries"); int radius_deadtime = rc_conf_int(rh, "radius_deadtime"); double start_time = 0; double now = 0; time_t dtime; unsigned type; if (request_type != PW_ACCOUNTING_REQUEST) { aaaserver = rc_conf_srv(rh, "authserver"); type = AUTH; } else { aaaserver = rc_conf_srv(rh, "acctserver"); type = ACCT; } if (aaaserver == NULL) return ERROR_RC; data.send_pairs = send; data.receive_pairs = NULL; if (add_nas_port != 0) { /* * Fill in NAS-Port */ if (rc_avpair_add(rh, &(data.send_pairs), PW_NAS_PORT, &client_port, 0, 0) == NULL) return ERROR_RC; } if (request_type == PW_ACCOUNTING_REQUEST) { /* * Fill in Acct-Delay-Time */ dtime = 0; now = rc_getctime(); adt_vp = rc_avpair_get(data.send_pairs, PW_ACCT_DELAY_TIME, 0); if (adt_vp == NULL) { adt_vp = rc_avpair_add(rh, &(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime, 0, 0); if (adt_vp == NULL) return ERROR_RC; start_time = now; } else { start_time = now - adt_vp->lvalue; } } skip_count = 0; result = ERROR_RC; for (i=0; (i < aaaserver->max) && (result != OK_RC) && (result != REJECT_RC) ; i++, now = rc_getctime()) { if (aaaserver->deadtime_ends[i] != -1 && aaaserver->deadtime_ends[i] > start_time) { skip_count++; continue; } if (data.receive_pairs != NULL) { rc_avpair_free(data.receive_pairs); data.receive_pairs = NULL; } rc_buildreq(rh, &data, request_type, aaaserver->name[i], aaaserver->port[i], aaaserver->secret[i], timeout, retries); if (request_type == PW_ACCOUNTING_REQUEST) { dtime = now - start_time; rc_avpair_assign(adt_vp, &dtime, 0); } result = rc_send_server (rh, &data, msg, type); if (result == TIMEOUT_RC && radius_deadtime > 0) aaaserver->deadtime_ends[i] = start_time + (double)radius_deadtime; } if (result == OK_RC || result == REJECT_RC || skip_count == 0) goto exit; result = ERROR_RC; for (i=0; (i < aaaserver->max) && (result != OK_RC) && (result != REJECT_RC) ; i++) { if (aaaserver->deadtime_ends[i] == -1 || aaaserver->deadtime_ends[i] <= start_time) { continue; } if (data.receive_pairs != NULL) { rc_avpair_free(data.receive_pairs); data.receive_pairs = NULL; } rc_buildreq(rh, &data, request_type, aaaserver->name[i], aaaserver->port[i], aaaserver->secret[i], timeout, retries); if (request_type == PW_ACCOUNTING_REQUEST) { dtime = rc_getctime() - start_time; rc_avpair_assign(adt_vp, &dtime, 0); } result = rc_send_server (rh, &data, msg, type); if (result != TIMEOUT_RC) aaaserver->deadtime_ends[i] = -1; } exit: if (request_type != PW_ACCOUNTING_REQUEST) { *received = data.receive_pairs; } else { rc_avpair_free(data.receive_pairs); } return result; }
int rc_send_server (rc_handle *rh, SEND_DATA *data, char *msg) { int sockfd; struct sockaddr_in sinlocal; struct sockaddr_in sinremote; AUTH_HDR *auth, *recv_auth; uint32_t auth_ipaddr, nas_ipaddr; char *server_name; /* Name of server to query */ socklen_t salen; int result = 0; int total_length; int length; int retry_max; size_t secretlen; char secret[MAX_SECRET_LENGTH + 1]; unsigned char vector[AUTH_VECTOR_LEN]; char recv_buffer[BUFFER_LEN]; char send_buffer[BUFFER_LEN]; 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 ((vp = rc_avpair_get(data->send_pairs, PW_SERVICE_TYPE, 0)) && \ (vp->lvalue == PW_ADMINISTRATIVE)) { strcpy(secret, MGMT_POLL_SECRET); if ((auth_ipaddr = rc_get_ipaddr(server_name)) == 0) return ERROR_RC; } else { if(data->secret != NULL) { strncpy(secret, data->secret, MAX_SECRET_LENGTH); } /* else { */ if (rc_find_server (rh, server_name, &auth_ipaddr, secret) != 0) { rc_log(LOG_ERR, "rc_send_server: unable to find server: %s", server_name); return ERROR_RC; } /*}*/ } DEBUG(LOG_ERR, "DEBUG: rc_send_server: creating socket to: %s", server_name); sockfd = socket (AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { memset (secret, '\0', sizeof (secret)); rc_log(LOG_ERR, "rc_send_server: socket: %s", strerror(errno)); return ERROR_RC; } memset((char *)&sinlocal, '\0', sizeof(sinlocal)); sinlocal.sin_family = AF_INET; sinlocal.sin_addr.s_addr = htonl(rc_own_bind_ipaddress(rh)); sinlocal.sin_port = htons((unsigned short) 0); if (bind(sockfd, SA(&sinlocal), sizeof(sinlocal)) < 0) { close (sockfd); memset (secret, '\0', sizeof (secret)); rc_log(LOG_ERR, "rc_send_server: bind: %s: %s", server_name, strerror(errno)); return ERROR_RC; } retry_max = data->retries; /* Max. numbers to try for reply */ retries = 0; /* Init retry cnt for blocking call */ memset ((char *)&sinremote, '\0', sizeof(sinremote)); sinremote.sin_family = AF_INET; sinremote.sin_addr.s_addr = htonl (auth_ipaddr); sinremote.sin_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) { if (sinlocal.sin_addr.s_addr == htonl(INADDR_ANY)) { if (rc_get_srcaddr(SA(&sinlocal), SA(&sinremote)) != 0) { close (sockfd); memset (secret, '\0', sizeof (secret)); return ERROR_RC; } } nas_ipaddr = ntohl(sinlocal.sin_addr.s_addr); rc_avpair_add(rh, &(data->send_pairs), PW_NAS_IP_ADDRESS, &nas_ipaddr, 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); } DEBUG(LOG_ERR, "DEBUG: local %s : 0, remote %s : %u\n", inet_ntoa(sinlocal.sin_addr), inet_ntoa(sinremote.sin_addr), data->svc_port); for (;;) { sendto (sockfd, (char *) auth, (unsigned int) total_length, (int) 0, SA(&sinremote), sizeof (struct sockaddr_in)); 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); return ERROR_RC; } 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, %s", rc_ip_hostname (auth_ipaddr), data->svc_port, inet_ntoa(sinremote.sin_addr)); close (sockfd); memset (secret, '\0', sizeof (secret)); return TIMEOUT_RC; } } salen = sizeof(sinremote); length = recvfrom (sockfd, (char *) recv_buffer, (int) sizeof (recv_buffer), (int) 0, SA(&sinremote), &salen); 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)); return ERROR_RC; } 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)); return ERROR_RC; } 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) return result; *msg = '\0'; vp = data->receive_pairs; while (vp) { if ((vp = rc_avpair_get(vp, PW_REPLY_MESSAGE, 0))) { strcat(msg, vp->strvalue); strcat(msg, "\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 { result = BADRESP_RC; } return result; }
/** 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. */ int rc_send_server (rc_handle *rh, SEND_DATA *data, char *msg, unsigned flags) { 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 ((vp = rc_avpair_get(data->send_pairs, PW_SERVICE_TYPE, 0)) && \ (vp->lvalue == PW_ADMINISTRATIVE)) { strcpy(secret, MGMT_POLL_SECRET); auth_addr = rc_getaddrinfo(server_name, flags==AUTH?PW_AI_AUTH:PW_AI_ACCT); if (auth_addr == NULL) return ERROR_RC; } else { if(data->secret != NULL) { strlcpy(secret, data->secret, MAX_SECRET_LENGTH); } /* else { */ 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; if(data->timeout_ms > 0){ start_time = rc_getctime_ms(); for (timeout = data->timeout_ms; timeout > 0;timeout -= rc_getctime_ms() - start_time) { result = poll(&pfd, 1, timeout ); if (result != -1 || errno != EINTR) break; } }else{ 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 { result = BADRESP_RC; } cleanup: if (auth_addr) freeaddrinfo(auth_addr); return result; }
//int rc_aaa(rc_handle *rh, char *host, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received, char *msg, int add_nas_port, int request_type) int rc_aaa(rc_handle *rh, const string & host, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received, char *msg, int add_nas_port, int request_type) { fprintf(stdout, "rc_aaa::Start\n"); SEND_DATA data; VALUE_PAIR *adt_vp; int result; int i, skip_count; SERVER aaaserver; int timeout = rc_conf_int(rh, "radius_timeout"); int retries = rc_conf_int(rh, "radius_retries"); int radius_deadtime = rc_conf_int(rh, "radius_deadtime"); double start_time; time_t dtime; if (request_type != PW_ACCOUNTING_REQUEST) { // aaaserver = rc_conf_srv(rh, "authserver"); // fprintf(stdout, "rc_aaa::authserver\n"); // rc_conf_srv(rh, "authserver", &aaaserver); // aaaserver.name = host; } else { // aaaserver = rc_conf_srv(rh, "acctserver"); // fprintf(stdout, "rc_aaa::acctserver\n"); } // char srvName[15] = "192.168.10.102"; // strcpy(srvName ,aaaserver.name); // fprintf(stdout, "srvName: %s\n", srvName); // fprintf(stdout, "aaaserver.name: %s\n", aaaserver.name); /* if (aaaserver == NULL) { return ERROR_RC; } */ if( !host.empty() ) { aaaserver.name = host; } data.send_pairs = send; data.receive_pairs = NULL; if (add_nas_port != 0) { /* * Fill in NAS-Port */ if (rc_avpair_add(rh, &(data.send_pairs), PW_NAS_PORT, &client_port, 0, 0) == NULL) return ERROR_RC; } if (request_type == PW_ACCOUNTING_REQUEST) { /* * Fill in Acct-Delay-Time */ dtime = 0; if ((adt_vp = rc_avpair_add(rh, &(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime, 0, 0)) == NULL) return ERROR_RC; } start_time = rc_getctime(); skip_count = 0; result = ERROR_RC; // fprintf(stdout, "rc_aaa::aaaserver.max %d\n", aaaserver.max); aaaserver.max = 1; for (i=0; (i < aaaserver.max) && (result != OK_RC) && (result != BADRESP_RC); i++) { if (aaaserver.deadtime_ends != -1 && aaaserver.deadtime_ends > start_time) { skip_count++; continue; } if (data.receive_pairs != NULL) { rc_avpair_free(data.receive_pairs); data.receive_pairs = NULL; } rc_buildreq(rh, &data, request_type, aaaserver.name.c_str(), aaaserver.port, aaaserver.secret.c_str(), timeout, retries); fprintf(stdout, "rc_buildreq: data.server: %s\n", data.server.c_str()); fprintf(stdout, "rc_buildreq: data.secret: %s\n", data.secret.c_str()); fprintf(stdout, "rc_buildreq: data.svc_port: %i\n", data.svc_port); // fprintf(stdout, "aaaserver.name %s, port: %s, secert %s\n", aaaserver.name[i], aaaserver.port[i], aaaserver.secret[i]); if (request_type == PW_ACCOUNTING_REQUEST) { dtime = rc_getctime() - start_time; rc_avpair_assign(adt_vp, &dtime, 0); } result = rc_send_server (rh, &data, msg); if (result == TIMEOUT_RC && radius_deadtime > 0) aaaserver.deadtime_ends = start_time + (double)radius_deadtime; } if (result == OK_RC || result == BADRESP_RC || skip_count == 0) goto exit; result = ERROR_RC; for (i=0; (i < aaaserver.max) && (result != OK_RC) && (result != BADRESP_RC) ; i++) { if (aaaserver.deadtime_ends == -1 || aaaserver.deadtime_ends <= start_time) { continue; } if (data.receive_pairs != NULL) { rc_avpair_free(data.receive_pairs); data.receive_pairs = NULL; } rc_buildreq(rh, &data, request_type, aaaserver.name.c_str(), aaaserver.port, aaaserver.secret.c_str(), timeout, retries); if (request_type == PW_ACCOUNTING_REQUEST) { dtime = rc_getctime() - start_time; rc_avpair_assign(adt_vp, &dtime, 0); } fprintf(stdout, "rc_aaa::rc_send_server Start\n"); result = rc_send_server (rh, &data, msg); fprintf(stdout, "rc_aaa::rc_send_server End\n"); if (result != TIMEOUT_RC) aaaserver.deadtime_ends = -1; } exit: if (request_type != PW_ACCOUNTING_REQUEST) { *received = data.receive_pairs; } else { rc_avpair_free(data.receive_pairs); } printf("rc_aaa return: %d\n", result); return result; }
/** Builds an authentication/accounting request for port id client_port with the value_pairs send and submits it to a specified server. * This function keeps its state in ctx after a successful operation. It can be deallocated using * rc_aaa_ctx_free(). * * @param rh a handle to parsed configuration. * @param ctx if non-NULL it will contain the context of the request; Its initial value should be NULL and it must be released using rc_aaa_ctx_free(). * @param aaaserver a non-NULL SERVER to send the message to. * @param client_port the client port number to use (may be zero to use any available). * @param send a VALUE_PAIR array of values (e.g., PW_USER_NAME). * @param received an allocated array of received values. * @param msg must be an array of PW_MAX_MSG_SIZE or NULL; will contain the concatenation of any * PW_REPLY_MESSAGE received. * @param add_nas_port if non-zero it will include PW_NAS_PORT in sent pairs. * @param request_type one of standard RADIUS codes (e.g., PW_ACCESS_REQUEST). * @return received value_pairs in received, messages from the server in msg and OK_RC (0) on success, negative * on failure as return value. */ int rc_aaa_ctx_server(rc_handle *rh, RC_AAA_CTX **ctx, SERVER *aaaserver, rc_type type, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received, char *msg, int add_nas_port, rc_standard_codes request_type) { SEND_DATA data; VALUE_PAIR *adt_vp = NULL; int result; int timeout = rc_conf_int(rh, "radius_timeout"); int retries = rc_conf_int(rh, "radius_retries"); double start_time = 0; double now = 0; time_t dtime; int servernum; data.send_pairs = send; data.receive_pairs = NULL; /* * if there is more than zero servers, then divide waiting time * among all the servers. */ if(aaaserver->max > 0) { if(timeout > 0) { timeout = (timeout+1) / aaaserver->max; } if(retries > 0) { retries = (retries+1) / aaaserver->max; } } if (add_nas_port != 0 && rc_avpair_get(data.send_pairs, PW_NAS_PORT, 0) == NULL) { /* * Fill in NAS-Port */ if (rc_avpair_add(rh, &(data.send_pairs), PW_NAS_PORT, &client_port, 0, 0) == NULL) return ERROR_RC; } if (request_type == PW_ACCOUNTING_REQUEST) { /* * Fill in Acct-Delay-Time */ dtime = 0; now = rc_getctime(); adt_vp = rc_avpair_get(data.send_pairs, PW_ACCT_DELAY_TIME, 0); if (adt_vp == NULL) { adt_vp = rc_avpair_add(rh, &(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime, 0, 0); if (adt_vp == NULL) return ERROR_RC; start_time = now; } else { start_time = now - adt_vp->lvalue; } } if (data.receive_pairs != NULL) { rc_avpair_free(data.receive_pairs); data.receive_pairs = NULL; } servernum=0; do { rc_buildreq(rh, &data, request_type, aaaserver->name[servernum], aaaserver->port[servernum], aaaserver->secret[servernum], timeout, retries); if (request_type == PW_ACCOUNTING_REQUEST) { dtime = rc_getctime() - start_time; rc_avpair_assign(adt_vp, &dtime, 0); } result = rc_send_server_ctx (rh, ctx, &data, msg, type); if (request_type != PW_ACCOUNTING_REQUEST) { *received = data.receive_pairs; } else { rc_avpair_free(data.receive_pairs); } if(result == OK_RC) { DEBUG(LOG_INFO, "servernum %u returned success", servernum); return result; } //rc_log(LOG_ERR, // "servernum %u returned error: %d", servernum, result); servernum++; } while(servernum < aaaserver->max && result == TIMEOUT_RC); return result; }