X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmain%2Fradclient.c;h=a14801d8606396b9bef26bb1da82dcf72b9598d1;hb=94dc4bb60ec649ce899c1d5e32b575d9523a48f2;hp=cd5b3aab8eef2fde0adc34441e58a1f26b797fcf;hpb=ddac2eeccdc6af9d710814d78a432c263100c42d;p=freeradius.git diff --git a/src/main/radclient.c b/src/main/radclient.c index cd5b3aa..a14801d 100644 --- a/src/main/radclient.c +++ b/src/main/radclient.c @@ -37,8 +37,12 @@ RCSID("$Id$") #include -static int retries = 10; -static float timeout = 3; +#include "smbdes.h" +#include "mschap.h" + +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; @@ -58,6 +62,11 @@ static int client_port = 0; static int sockfd; 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 fr_packet_list_t *pl = NULL; @@ -102,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); } @@ -139,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); /* @@ -161,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; @@ -178,18 +228,25 @@ static radclient_t *radclient_init(const char *filename) if (!radclient) { perror("radclient: X"); if (fp != stdin) fclose(fp); - return NULL; /* memory leak "start" */ + return 0; } memset(radclient, 0, sizeof(*radclient)); radclient->request = rad_alloc(1); if (!radclient->request) { fr_perror("radclient: Y"); - radclient_free(radclient); + free(radclient); if (fp != stdin) fclose(fp); - return NULL; /* memory leak "start" */ + 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++; @@ -199,21 +256,26 @@ static radclient_t *radclient_init(const char *filename) */ radclient->request->vps = readvp2(fp, &filedone, "radclient:"); if (!radclient->request->vps) { - radclient_free(radclient); + rad_free(&radclient->request); + free(radclient); if (fp != stdin) fclose(fp); - return start; /* done: return the list */ + return 1; } /* * Keep a copy of the the User-Password attribute. */ - if ((vp = pairfind(radclient->request->vps, PW_USER_PASSWORD)) != NULL) { + 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) { + } 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 { @@ -285,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); @@ -300,7 +369,7 @@ static radclient_t *radclient_init(const char *filename) /* * And we're done. */ - return start; + return 1; } @@ -346,35 +415,16 @@ 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; } @@ -500,16 +550,27 @@ static int send_one_packet(radclient_t *radclient) * this packet. */ retry: - rcode = fr_packet_list_id_alloc(pl, radclient->request); + 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)) { + 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); } @@ -536,12 +597,12 @@ static int send_one_packet(radclient_t *radclient) if (radclient->password[0] != '\0') { VALUE_PAIR *vp; - if ((vp = pairfind(radclient->request->vps, PW_USER_PASSWORD)) != NULL) { + 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 @@ -555,6 +616,12 @@ static int send_one_packet(radclient_t *radclient) vp->vp_octets, radclient->request->id, vp); vp->length = 17; + + } else if (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"); } } @@ -569,6 +636,16 @@ static int send_one_packet(radclient_t *radclient) 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); @@ -676,10 +753,19 @@ static int recv_one_packet(int wait_time) /* * Look for the packet. */ + reply = fr_packet_list_recv(pl, &set); if (!reply) { fprintf(stderr, "radclient: received bad packet: %s\n", 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 */ } @@ -689,6 +775,11 @@ static int recv_one_packet(int wait_time) * (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 if (fr_debug_flag > 2) print_hex(reply); @@ -717,11 +808,12 @@ static int recv_one_packet(int wait_time) 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) { + if (rad_decode(radclient->reply, radclient->request, secret) != 0) { fr_perror("rad_decode"); totallost++; goto packet_done; @@ -729,11 +821,17 @@ static int recv_one_packet(int wait_time) /* libradius debug already prints out the value pairs for us */ if (!fr_debug_flag && do_output) { - printf("Received response ID %d, code %d, length = %d\n", - reply->id, reply->code, reply->data_len); - vp_printlist(stdout, reply->vps); + 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++; @@ -745,6 +843,7 @@ static int recv_one_packet(int wait_time) packet_done: rad_free(&radclient->reply); + rad_free(&reply); /* may be NULL */ return 0; } @@ -783,7 +882,11 @@ int main(int argc, char **argv) exit(1); } - while ((c = getopt(argc, argv, "46c:d:f:Fhi: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; @@ -830,6 +933,22 @@ int main(int argc, char **argv) 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! */ @@ -877,7 +996,7 @@ 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': @@ -905,6 +1024,7 @@ int main(int argc, char **argv) /* * 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]; @@ -968,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) { @@ -1025,6 +1145,11 @@ int main(int argc, char **argv) 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()); @@ -1037,7 +1162,8 @@ int main(int argc, char **argv) exit(1); } - if (!fr_packet_list_socket_add(pl, sockfd)) { + if (!fr_packet_list_socket_add(pl, sockfd, ipproto, &server_ipaddr, + server_port, NULL)) { fprintf(stderr, "radclient: Out of memory\n"); exit(1); } @@ -1185,6 +1311,7 @@ int main(int argc, char **argv) rbtree_free(filename_tree); fr_packet_list_free(pl); + while (radclient_head) radclient_free(radclient_head); dict_free(); if (do_summary) { @@ -1193,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; }