X-Git-Url: http://www.project-moonshot.org/gitweb/?p=freeradius.git;a=blobdiff_plain;f=src%2Fmain%2Fradclient.c;h=42cb088c6200db5a9917881b7f4d17f3d9bf3816;hp=a09793ff0063b1bc18f6adb985a1d3fb093898df;hb=dda8981f264c5e4f5907f2fced69e04a220f134b;hpb=b21e7599ddb6a702c1a15e29397e3974de84f5c7 diff --git a/src/main/radclient.c b/src/main/radclient.c index a09793f..42cb088 100644 --- a/src/main/radclient.c +++ b/src/main/radclient.c @@ -15,35 +15,21 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * - * Copyright 2000 The FreeRADIUS server project + * Copyright 2000,2006 The FreeRADIUS server project * Copyright 2000 Miquel van Smoorenburg * Copyright 2000 Alan DeKok */ -static const char rcsid[] = "$Id$"; -#include +#include +RCSID("$Id$") -#include -#include - -#ifdef HAVE_UNISTD_H -# include -#endif +#include +#include +#include -#include #include -#include -#include - -#ifdef HAVE_NETINET_IN_H -# include -#endif - -#ifdef HAVE_SYS_SELECT_H -# include -#endif #ifdef HAVE_GETOPT_H # include @@ -51,13 +37,12 @@ static const char rcsid[] = "$Id$"; #include -#include -#include -#include -#include +#include "smbdes.h" +#include "mschap.h" -static int retries = 10; -static float timeout = 3; +static int success = 0; +static int retries = 3; +static float timeout = 5; static const char *secret = NULL; static int do_output = 1; static int totalapp = 0; @@ -66,16 +51,24 @@ static int totallost = 0; static int server_port = 0; static int packet_code = 0; -static lrad_ipaddr_t server_ipaddr; +static fr_ipaddr_t server_ipaddr; static int resend_count = 1; static int done = 1; +static int print_filename = 0; + +static fr_ipaddr_t client_ipaddr; +static int client_port = 0; static int sockfd; -static int radius_id[256]; static int last_used_id = -1; +#ifdef WITH_TCP +const char *proto = NULL; +#endif +static int ipproto = IPPROTO_UDP; + static rbtree_t *filename_tree = NULL; -static rbtree_t *request_tree = NULL; +static fr_packet_list_t *pl = NULL; static int sleep_time = -1; @@ -118,6 +111,9 @@ static void NEVER_RETURNS usage(void) fprintf(stderr, " -x Debugging mode.\n"); fprintf(stderr, " -4 Use IPv4 address of server\n"); fprintf(stderr, " -6 Use IPv6 address of server.\n"); +#ifdef WITH_TCP + fprintf(stderr, " -P proto Use proto (tcp or udp) for transport.\n"); +#endif exit(1); } @@ -155,18 +151,56 @@ static void radclient_free(radclient_t *radclient) free(radclient); } +static int mschapv1_encode(VALUE_PAIR **request, const char *password) +{ + unsigned int i; + VALUE_PAIR *challenge, *response; + uint8_t nthash[16]; + + challenge = paircreate(PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT, PW_TYPE_OCTETS); + if (!challenge) { + fprintf(stderr, "GOT IT %d!\n", __LINE__); + return 0; + } + + pairadd(request, challenge); + challenge->length = 8; + for (i = 0; i < challenge->length; i++) { + challenge->vp_octets[i] = fr_rand(); + } + + response = paircreate(PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT, PW_TYPE_OCTETS); + if (!response) { + fprintf(stderr, "GOT IT %d!\n", __LINE__); + return 0; + } + + pairadd(request, response); + response->length = 50; + memset(response->vp_octets, 0, response->length); + + response->vp_octets[1] = 0x01; /* NT hash */ + + mschap_ntpwdhash(nthash, password); + + smbdes_mschap(nthash, challenge->vp_octets, + response->vp_octets + 26); + return 1; +} + + /* - * Initialize a radclient data structure + * Initialize a radclient data structure and add it to + * the global linked list. */ -static radclient_t *radclient_init(const char *filename) +static int radclient_init(const char *filename) { FILE *fp; VALUE_PAIR *vp; - radclient_t *start, *radclient, *prev = NULL; + radclient_t *radclient; int filedone = 0; int packet_number = 1; - start = NULL; assert(filename != NULL); /* @@ -177,7 +211,7 @@ static radclient_t *radclient_init(const char *filename) if (!fp) { fprintf(stderr, "radclient: Error opening %s: %s\n", filename, strerror(errno)); - return NULL; + return 0; } } else { fp = stdin; @@ -192,18 +226,27 @@ static radclient_t *radclient_init(const char *filename) */ radclient = malloc(sizeof(*radclient)); if (!radclient) { - perror("radclient: "); - return NULL; /* memory leak "start" */ + perror("radclient: X"); + if (fp != stdin) fclose(fp); + return 0; } memset(radclient, 0, sizeof(*radclient)); radclient->request = rad_alloc(1); if (!radclient->request) { - librad_perror("radclient: "); - radclient_free(radclient); - return NULL; /* memory leak "start" */ + fr_perror("radclient: Y"); + free(radclient); + if (fp != stdin) fclose(fp); + return 0; } +#ifdef WITH_TCP + radclient->request->src_ipaddr = client_ipaddr; + radclient->request->src_port = client_port; + radclient->request->dst_ipaddr = server_ipaddr; + radclient->request->dst_port = server_port; +#endif + radclient->filename = filename; radclient->request->id = -1; /* allocate when sending */ radclient->packet_number = packet_number++; @@ -213,21 +256,27 @@ static radclient_t *radclient_init(const char *filename) */ radclient->request->vps = readvp2(fp, &filedone, "radclient:"); if (!radclient->request->vps) { - radclient_free(radclient); - return start; /* done: return the list */ + rad_free(&radclient->request); + free(radclient); + if (fp != stdin) fclose(fp); + return 1; } /* * Keep a copy of the the User-Password attribute. */ - if ((vp = pairfind(radclient->request->vps, PW_PASSWORD)) != NULL) { - strNcpy(radclient->password, vp->vp_strvalue, + if ((vp = pairfind(radclient->request->vps, PW_USER_PASSWORD, 0)) != NULL) { + strlcpy(radclient->password, vp->vp_strvalue, sizeof(radclient->password)); /* * Otherwise keep a copy of the CHAP-Password attribute. */ - } else if ((vp = pairfind(radclient->request->vps, PW_CHAP_PASSWORD)) != NULL) { - strNcpy(radclient->password, vp->vp_strvalue, + } else if ((vp = pairfind(radclient->request->vps, PW_CHAP_PASSWORD, 0)) != NULL) { + strlcpy(radclient->password, vp->vp_strvalue, + sizeof(radclient->password)); + + } else if ((vp = pairfind(radclient->request->vps, PW_MSCHAP_PASSWORD, 0)) != NULL) { + strlcpy(radclient->password, vp->vp_strvalue, sizeof(radclient->password)); } else { radclient->password[0] = '\0'; @@ -246,16 +295,16 @@ static radclient_t *radclient_init(const char *filename) * the attributes read from the file. */ case PW_PACKET_TYPE: - radclient->request->code = vp->lvalue; + radclient->request->code = vp->vp_integer; break; case PW_PACKET_DST_PORT: - radclient->request->dst_port = (vp->lvalue & 0xffff); + radclient->request->dst_port = (vp->vp_integer & 0xffff); break; case PW_PACKET_DST_IP_ADDRESS: radclient->request->dst_ipaddr.af = AF_INET; - radclient->request->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->lvalue; + radclient->request->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; break; case PW_PACKET_DST_IPV6_ADDRESS: @@ -264,12 +313,12 @@ static radclient_t *radclient_init(const char *filename) break; case PW_PACKET_SRC_PORT: - radclient->request->src_port = (vp->lvalue & 0xffff); + radclient->request->src_port = (vp->vp_integer & 0xffff); break; case PW_PACKET_SRC_IP_ADDRESS: radclient->request->src_ipaddr.af = AF_INET; - radclient->request->src_ipaddr.ipaddr.ip4addr.s_addr = vp->lvalue; + radclient->request->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; break; case PW_PACKET_SRC_IPV6_ADDRESS: @@ -298,14 +347,21 @@ static radclient_t *radclient_init(const char *filename) } } /* loop over the VP's we read in */ - if (!start) { - start = radclient; - prev = start; + /* + * Add it to the tail of the list. + */ + if (!radclient_head) { + assert(radclient_tail == NULL); + radclient_head = radclient; + radclient->prev = NULL; } else { - prev->next = radclient; - radclient->prev = prev; - prev = radclient; + assert(radclient_tail->next == NULL); + radclient_tail->next = radclient; + radclient->prev = radclient_tail; } + radclient_tail = radclient; + radclient->next = NULL; + } while (!filedone); /* loop until the file is done. */ if (fp != stdin) fclose(fp); @@ -313,7 +369,7 @@ static radclient_t *radclient_init(const char *filename) /* * And we're done. */ - return start; + return 1; } @@ -342,7 +398,7 @@ static int radclient_sane(radclient_t *radclient) radclient->request->code = packet_code; } - radclient->request->sockfd = sockfd; + radclient->request->sockfd = -1; return 0; } @@ -359,92 +415,25 @@ static int filename_cmp(const void *one, const void *two) static int filename_walk(void *context, void *data) { const char *filename = data; - radclient_t *radclient; context = context; /* -Wunused */ /* - * Initialize the request we're about - * to send. + * Read request(s) from the file. */ - radclient = radclient_init(filename); - if (!radclient) { - exit(1); - } - - if (!radclient_head) { - assert(radclient_tail == NULL); - radclient_head = radclient; - } else { - assert(radclient_tail->next == NULL); - radclient_tail->next = radclient; - radclient->prev = radclient_tail; + if (!radclient_init(filename)) { + return 1; /* stop walking */ } - /* - * We may have had a list of "radclient" structures - * returned to us. - */ - while (radclient->next) radclient = radclient->next; - radclient_tail = radclient; - return 0; } /* - * Compare two RADIUS_PACKET data structures, based on a number - * of criteria. + * Deallocate packet ID, etc. */ -static int request_cmp(const void *one, const void *two) +static void deallocate_id(radclient_t *radclient) { - int rcode; - const radclient_t *a = one; - const radclient_t *b = two; - - /* - * The following code looks unreasonable, but it's - * the only way to make the comparisons work. - */ - if (a->request->id < b->request->id) return -1; - if (a->request->id > b->request->id) return +1; - - if (a->request->dst_ipaddr.af < b->request->dst_ipaddr.af) return -1; - if (a->request->dst_ipaddr.af > b->request->dst_ipaddr.af) return +1; - - switch (a->request->dst_ipaddr.af) { - case AF_INET: - rcode = memcmp(&a->request->dst_ipaddr.ipaddr.ip4addr, - &b->request->dst_ipaddr.ipaddr.ip4addr, - sizeof(a->request->dst_ipaddr.ipaddr.ip4addr)); - break; - case AF_INET6: - rcode = memcmp(&a->request->dst_ipaddr.ipaddr.ip6addr, - &b->request->dst_ipaddr.ipaddr.ip6addr, - sizeof(a->request->dst_ipaddr.ipaddr.ip6addr)); - break; - default: /* FIXME: die! */ - return -1; - break; - } - if (rcode != 0) return rcode; - - if (a->request->dst_port < b->request->dst_port) return -1; - if (a->request->dst_port > b->request->dst_port) return +1; - - /* - * Everything's equal. Say so. - */ - return 0; -} - -/* - * "Free" a request. - */ -static void request_free(void *data) -{ - radclient_t *radclient = (radclient_t *) data; - if (!radclient || !radclient->request || (radclient->request->id < 0)) { return; @@ -453,7 +442,7 @@ static void request_free(void *data) /* * One more unused RADIUS ID. */ - radius_id[radclient->request->id] = 0; + fr_packet_list_id_free(pl, radclient->request); radclient->request->id = -1; /* @@ -485,7 +474,7 @@ static void print_hex(RADIUS_PACKET *packet) printf("%02x", packet->data[i]); } printf("\n"); - + if (packet->data_len > 20) { int total; const uint8_t *ptr; @@ -536,8 +525,6 @@ static void print_hex(RADIUS_PACKET *packet) */ static int send_one_packet(radclient_t *radclient) { - int i; - assert(radclient->done == 0); /* @@ -553,29 +540,44 @@ static int send_one_packet(radclient_t *radclient) * Haven't sent the packet yet. Initialize it. */ if (radclient->request->id == -1) { - int found = 0; + int i, rcode; assert(radclient->reply == NULL); /* - * Find a free packet Id - */ - for (i = 0; i < 256; i++) { - if (radius_id[(last_used_id + i) & 0xff] == 0) { - last_used_id = (last_used_id + i) & 0xff; - radius_id[last_used_id] = 1; - radclient->request->id = last_used_id++; - found = 1; - break; - } - } - - /* * Didn't find a free packet ID, we're not done, * we don't sleep, and we stop trying to process * this packet. */ - if (!found) { + retry: + radclient->request->src_ipaddr.af = server_ipaddr.af; + rcode = fr_packet_list_id_alloc(pl, ipproto, + radclient->request, NULL); + if (rcode < 0) { + int mysockfd; + +#ifdef WITH_TCP + if (proto) { + mysockfd = fr_tcp_client_socket(NULL, + &server_ipaddr, + server_port); + } else +#endif + mysockfd = fr_socket(&client_ipaddr, 0); + if (!mysockfd) { + fprintf(stderr, "radclient: Can't open new socket\n"); + exit(1); + } + if (!fr_packet_list_socket_add(pl, mysockfd, ipproto, + &server_ipaddr, + server_port, NULL)) { + fprintf(stderr, "radclient: Can't add new socket\n"); + exit(1); + } + goto retry; + } + + if (rcode == 0) { done = 0; sleep_time = 0; return 0; @@ -584,8 +586,9 @@ static int send_one_packet(radclient_t *radclient) assert(radclient->request->id != -1); assert(radclient->request->data == NULL); - librad_md5_calc(radclient->request->vector, radclient->request->vector, - sizeof(radclient->request->vector)); + for (i = 0; i < 4; i++) { + ((uint32_t *) radclient->request->vector)[i] = fr_rand(); + } /* * Update the password, so it can be encrypted with the @@ -594,18 +597,18 @@ static int send_one_packet(radclient_t *radclient) if (radclient->password[0] != '\0') { VALUE_PAIR *vp; - if ((vp = pairfind(radclient->request->vps, PW_PASSWORD)) != NULL) { - strNcpy(vp->vp_strvalue, radclient->password, + if ((vp = pairfind(radclient->request->vps, PW_USER_PASSWORD, 0)) != NULL) { + strlcpy(vp->vp_strvalue, radclient->password, sizeof(vp->vp_strvalue)); vp->length = strlen(vp->vp_strvalue); - } else if ((vp = pairfind(radclient->request->vps, PW_CHAP_PASSWORD)) != NULL) { + } else if ((vp = pairfind(radclient->request->vps, PW_CHAP_PASSWORD, 0)) != NULL) { /* * FIXME: AND there's no CHAP-Challenge, * AND vp->length != 17 * AND rad_chap_encode() != vp->vp_octets */ - strNcpy(vp->vp_strvalue, radclient->password, + strlcpy(vp->vp_strvalue, radclient->password, sizeof(vp->vp_strvalue)); vp->length = strlen(vp->vp_strvalue); @@ -613,6 +616,12 @@ static int send_one_packet(radclient_t *radclient) vp->vp_octets, radclient->request->id, vp); vp->length = 17; + + } else if ((vp = pairfind(radclient->request->vps, PW_MSCHAP_PASSWORD, 0)) != NULL) { + mschapv1_encode(&radclient->request->vps, + radclient->password); + } else if (fr_debug_flag) { + printf("WARNING: No password in the request\n"); } } @@ -623,10 +632,20 @@ static int send_one_packet(radclient_t *radclient) /* * Duplicate found. Serious error! */ - if (rbtree_insert(request_tree, radclient) == 0) { + if (!fr_packet_list_insert(pl, &radclient->request)) { assert(0 == 1); } +#ifdef WITH_TCP + /* + * WTF? + */ + if (client_port == 0) { + client_ipaddr = radclient->request->src_ipaddr; + client_port = radclient->request->src_port; + } +#endif + } else { /* radclient->request->id >= 0 */ time_t now = time(NULL); @@ -657,19 +676,17 @@ static int send_one_packet(radclient_t *radclient) * We're not trying later, maybe the packet is done. */ if (radclient->tries == retries) { - rbnode_t *node; assert(radclient->request->id >= 0); - + /* * Delete the request from the tree of * outstanding requests. */ - node = rbtree_find(request_tree, radclient); - assert(node != NULL); - - fprintf(stderr, "radclient: no response from server for ID %d\n", radclient->request->id); - rbtree_delete(request_tree, node); - + fr_packet_list_yank(pl, radclient->request); + + fprintf(stderr, "radclient: no response from server for ID %d socket %d\n", radclient->request->id, radclient->request->sockfd); + deallocate_id(radclient); + /* * Normally we mark it "done" when we've received * the response, but this is a special case. @@ -694,10 +711,10 @@ static int send_one_packet(radclient_t *radclient) */ if (rad_send(radclient->request, NULL, secret) < 0) { fprintf(stderr, "radclient: Failed to send packet for ID %d: %s\n", - radclient->request->id, librad_errstr); + radclient->request->id, fr_strerror()); } - if (librad_debug > 2) print_hex(radclient->request); + if (fr_debug_flag > 2) print_hex(radclient->request); return 0; } @@ -709,14 +726,15 @@ static int recv_one_packet(int wait_time) { fd_set set; struct timeval tv; - radclient_t myclient, *radclient; - RADIUS_PACKET myrequest, *reply; - rbnode_t *node; - + radclient_t *radclient; + RADIUS_PACKET *reply, **request_p; + volatile int max_fd; /* And wait for reply, timing out as necessary */ FD_ZERO(&set); - FD_SET(sockfd, &set); + + max_fd = fr_packet_list_fd_set(pl, &set); + if (max_fd < 0) exit(1); /* no sockets to listen on! */ if (wait_time <= 0) { tv.tv_sec = 0; @@ -728,86 +746,105 @@ static int recv_one_packet(int wait_time) /* * No packet was received. */ - if (select(sockfd + 1, &set, NULL, NULL, &tv) != 1) { + if (select(max_fd, &set, NULL, NULL, &tv) <= 0) { return 0; } /* * Look for the packet. */ - reply = rad_recv(sockfd); + + reply = fr_packet_list_recv(pl, &set); if (!reply) { fprintf(stderr, "radclient: received bad packet: %s\n", - librad_errstr); + fr_strerror()); +#ifdef WITH_TCP + /* + * If the packet is bad, we close the socket. + * I'm not sure how to do that now, so we just + * die... + */ + if (proto) exit(1); +#endif return -1; /* bad packet */ } - if (librad_debug > 2) print_hex(reply); + /* + * udpfromto issues. We may have bound to "*", + * and we want to find the replies that are sent to + * (say) 127.0.0.1. + */ + reply->dst_ipaddr = client_ipaddr; + reply->dst_port = client_port; +#ifdef WITH_TCP + reply->src_ipaddr = server_ipaddr; + reply->src_port = server_port; +#endif - myclient.request = &myrequest; - myrequest.id = reply->id; - myrequest.dst_ipaddr = reply->src_ipaddr; - myrequest.dst_port = reply->src_port; + if (fr_debug_flag > 2) print_hex(reply); - node = rbtree_find(request_tree, &myclient); - if (!node) { - fprintf(stderr, "radclient: received response to request we did not send. (%d)\n", myrequest.id); + request_p = fr_packet_list_find_byreply(pl, reply); + if (!request_p) { + fprintf(stderr, "radclient: received response to request we did not send. (id=%d socket %d)\n", reply->id, reply->sockfd); rad_free(&reply); return -1; /* got reply to packet we didn't send */ } - - radclient = rbtree_node2data(request_tree, node); - assert(radclient != NULL); - rbtree_delete(request_tree, node); - assert(radclient->request->id == -1); - assert(radclient->request->data == NULL); - - assert(radclient->reply == NULL); - radclient->reply = reply; + radclient = fr_packet2myptr(radclient_t, request, request_p); /* * Fails the signature validation: not a real reply. * FIXME: Silently drop it and listen for another packet. */ if (rad_verify(reply, radclient->request, secret) < 0) { - librad_perror("rad_verify"); + fr_perror("rad_verify"); totallost++; goto packet_done; /* shared secret is incorrect */ } + fr_packet_list_yank(pl, radclient->request); + if (print_filename) printf("%s:%d %d\n", + radclient->filename, + radclient->packet_number, + reply->code); + deallocate_id(radclient); + radclient->reply = reply; + reply = NULL; + /* * If this fails, we're out of memory. */ - if (rad_decode(reply, radclient->request, secret) != 0) { - librad_perror("rad_decode"); + if (rad_decode(radclient->reply, radclient->request, secret) != 0) { + fr_perror("rad_decode"); totallost++; goto packet_done; } /* libradius debug already prints out the value pairs for us */ - if (!librad_debug && do_output) { - printf("Received response ID %d, code %d, length = %d\n", - reply->id, reply->code, reply->data_len); - vp_printlist(stdout, reply->vps); + if (!fr_debug_flag && do_output) { + printf("Received response ID %d, code %d, length = %ld\n", + radclient->reply->id, radclient->reply->code, + radclient->reply->data_len); + vp_printlist(stdout, radclient->reply->vps); } - if (reply->code != PW_AUTHENTICATION_REJECT) { + + if ((radclient->reply->code == PW_AUTHENTICATION_ACK) || + (radclient->reply->code == PW_ACCOUNTING_RESPONSE) || + (radclient->reply->code == PW_COA_ACK) || + (radclient->reply->code == PW_DISCONNECT_ACK)) { + success = 1; /* have a good response */ totalapp++; } else { totaldeny++; } - -packet_done: - rad_free(&radclient->reply); - - /* - * Once we've sent the packet as many times as requested, - * mark it done. - */ + if (radclient->resend == resend_count) { - assert((node = rbtree_find(request_tree, radclient)) == NULL); radclient->done = 1; } + packet_done: + rad_free(&radclient->reply); + rad_free(&reply); /* may be NULL */ + return 0; } @@ -836,11 +873,8 @@ int main(int argc, char **argv) int parallel = 1; radclient_t *this; int force_af = AF_UNSPEC; - int len = 0; - struct sockaddr_storage ss; - struct sockaddr_in *s4; - librad_debug = 0; + fr_debug_flag = 0; filename_tree = rbtree_create(filename_cmp, NULL, 0); if (!filename_tree) { @@ -848,13 +882,11 @@ int main(int argc, char **argv) exit(1); } - request_tree = rbtree_create(request_cmp, request_free, 0); - if (!request_tree) { - fprintf(stderr, "radclient: Out of memory\n"); - exit(1); - } - - while ((c = getopt(argc, argv, "46c:d:f:hi:n:p:qr:sS:t:vx")) != EOF) switch(c) { + while ((c = getopt(argc, argv, "46c:d:f:Fhi:n:p:qr:sS:t:vx" +#ifdef WITH_TCP + "P:" +#endif + )) != EOF) switch(c) { case '4': force_af = AF_INET; break; @@ -872,7 +904,10 @@ int main(int argc, char **argv) case 'f': rbtree_insert(filename_tree, optarg); break; - case 'i': + case 'F': + print_filename = 1; + break; + case 'i': /* currently broken */ if (!isdigit((int) *optarg)) usage(); last_used_id = atoi(optarg); @@ -886,13 +921,37 @@ int main(int argc, char **argv) if (persec <= 0) usage(); break; + /* + * Note that sending MANY requests in + * parallel can over-run the kernel + * queues, and Linux will happily discard + * packets. So even if the server responds, + * the client may not see the response. + */ case 'p': parallel = atoi(optarg); if (parallel <= 0) usage(); break; +#ifdef WITH_TCP + case 'P': + proto = optarg; + if (strcmp(proto, "tcp") != 0) { + if (strcmp(proto, "udp") == 0) { + proto = NULL; + } else { + usage(); + } + } else { + ipproto = IPPROTO_TCP; + } + break; + +#endif + case 'q': do_output = 0; + fr_log_fp = NULL; /* no output from you, either! */ break; case 'r': if (!isdigit((int) *optarg)) @@ -937,11 +996,12 @@ int main(int argc, char **argv) timeout = atof(optarg); break; case 'v': - printf("radclient: $Id$ built on " __DATE__ " at " __TIME__ "\n"); + printf("radclient: " RADIUSD_VERSION " built on " __DATE__ " at " __TIME__ "\n"); exit(0); break; case 'x': - librad_debug++; + fr_debug_flag++; + fr_log_fp = stdout; break; case 'h': default: @@ -957,13 +1017,14 @@ int main(int argc, char **argv) } if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) { - librad_perror("radclient"); + fr_perror("radclient"); return 1; } /* * Resolve hostname. */ + if (force_af == AF_UNSPEC) force_af = AF_INET; server_ipaddr.af = force_af; if (strcmp(argv[1], "-") != 0) { const char *hostname = argv[1]; @@ -972,10 +1033,10 @@ int main(int argc, char **argv) if (*argv[1] == '[') { /* IPv6 URL encoded */ p = strchr(argv[1], ']'); - if ((p - argv[1]) >= sizeof(buffer)) { + if ((size_t) (p - argv[1]) >= sizeof(buffer)) { usage(); } - + memcpy(buffer, argv[1] + 1, p - argv[1] - 1); buffer[p - argv[1] - 1] = '\0'; @@ -992,7 +1053,7 @@ int main(int argc, char **argv) } if (ip_hton(hostname, force_af, &server_ipaddr) < 0) { - fprintf(stderr, "radclient: Failed to find IP address for host %s: %s\n", argv[1], strerror(errno)); + fprintf(stderr, "radclient: Failed to find IP address for host %s: %s\n", hostname, strerror(errno)); exit(1); } @@ -1002,8 +1063,6 @@ int main(int argc, char **argv) if (portname) server_port = atoi(portname); } - memset(radius_id, 0, sizeof(radius_id)); - /* * See what kind of request we want to send. */ @@ -1029,11 +1088,11 @@ int main(int argc, char **argv) packet_code = PW_STATUS_SERVER; } else if (strcmp(argv[2], "disconnect") == 0) { - if (server_port == 0) server_port = PW_POD_UDP_PORT; + if (server_port == 0) server_port = PW_COA_UDP_PORT; packet_code = PW_DISCONNECT_REQUEST; } else if (strcmp(argv[2], "coa") == 0) { - if (server_port == 0) server_port = PW_POD_UDP_PORT; + if (server_port == 0) server_port = PW_COA_UDP_PORT; packet_code = PW_COA_REQUEST; } else if (strcmp(argv[2], "auto") == 0) { @@ -1075,54 +1134,38 @@ int main(int argc, char **argv) } /* - * Bind only if Packet-Src-IP(v6)Address Attribute is found + * Bind to the first specified IP address and port. + * This means we ignore later ones. */ - switch (radclient_head->request->src_ipaddr.af) { - case AF_UNSPEC: - default: - /* - * Grab the socket. - */ - if ((sockfd = socket(server_ipaddr.af, SOCK_DGRAM, 0)) < 0) { - perror("radclient: socket: "); - exit(1); - } - break; - -#ifdef HAVE_STRUCT_SOCKADDR_IN6 - case AF_INET6: - { - struct sockaddr_in6 *s6; - s6 = (struct sockaddr_in6 *)&ss; - len = sizeof(struct sockaddr_in6); - s6->sin6_family = AF_INET6; - s6->sin6_flowinfo = 0; - s6->sin6_port = htons(radclient_head->request->src_port); - memcpy(&s6->sin6_addr, &radclient_head->request->src_ipaddr.ipaddr, 16); - } - goto sock_bind; + if (radclient_head->request->src_ipaddr.af == AF_UNSPEC) { + memset(&client_ipaddr, 0, sizeof(client_ipaddr)); + client_ipaddr.af = server_ipaddr.af; + client_port = 0; + } else { + client_ipaddr = radclient_head->request->src_ipaddr; + client_port = radclient_head->request->src_port; + } +#ifdef WITH_TCP + if (proto) { + sockfd = fr_tcp_client_socket(NULL, &server_ipaddr, server_port); + } else #endif + sockfd = fr_socket(&client_ipaddr, client_port); + if (sockfd < 0) { + fprintf(stderr, "radclient: socket: %s\n", fr_strerror()); + exit(1); + } - case AF_INET: - s4 = (struct sockaddr_in *)&ss; - len = sizeof(struct sockaddr_in); - s4->sin_family = AF_INET; - s4->sin_port = htons(radclient_head->request->src_port); - memcpy(&s4->sin_addr, &radclient_head->request->src_ipaddr.ipaddr, 4); - goto sock_bind; - - sock_bind: - if ((sockfd = socket(radclient_head->request->src_ipaddr.af, - SOCK_DGRAM, 0)) < 0) { + pl = fr_packet_list_create(1); + if (!pl) { + fprintf(stderr, "radclient: Out of memory\n"); + exit(1); + } - perror("radclient: socket: "); - exit(1); - } - if (bind(sockfd, (struct sockaddr *)&ss, len) < 0) { - perror("radclient: bind: "); - exit(1); - } - break; + if (!fr_packet_list_socket_add(pl, sockfd, ipproto, &server_ipaddr, + server_port, NULL)) { + fprintf(stderr, "radclient: Out of memory\n"); + exit(1); } /* @@ -1130,13 +1173,13 @@ int main(int argc, char **argv) * everything. */ for (this = radclient_head; this != NULL; this = this->next) { + this->request->src_ipaddr = client_ipaddr; + this->request->src_port = client_port; if (radclient_sane(this) != 0) { exit(1); } } - if (last_used_id < 0) last_used_id = getpid() & 0xff; - /* * Walk over the packets to send, until * we're all done. @@ -1217,7 +1260,7 @@ int main(int argc, char **argv) tv.tv_sec = 0; tv.tv_usec = 1000000/persec; } - + /* * Sleep for milliseconds, * portably. @@ -1248,7 +1291,7 @@ int main(int argc, char **argv) /* * Still have outstanding requests. */ - if (rbtree_num_elements(request_tree) > 0) { + if (fr_packet_list_num_elements(pl) > 0) { done = 0; } else { sleep_time = 0; @@ -1267,7 +1310,9 @@ int main(int argc, char **argv) } while (!done); rbtree_free(filename_tree); - rbtree_free(request_tree); + fr_packet_list_free(pl); + while (radclient_head) radclient_free(radclient_head); + dict_free(); if (do_summary) { printf("\n\t Total approved auths: %d\n", totalapp); @@ -1275,5 +1320,7 @@ int main(int argc, char **argv) printf("\t Total lost auths: %d\n", totallost); } - return 0; + if (success) return 0; + + return 1; }