#include #include #include #include #include #include #include #include #include "radius.h" #define MAXPWNAM 32 #define MAXPASS 16 char recv_buffer[4096]; char send_buffer[4096]; char *progname; int sockfd; char vector[AUTH_VECTOR_LEN]; char *secretkey; int debug_flag = 1; /* * Receive UDP client requests, build an authorization request * structure, and attach attribute-value pairs contained in * the request to the new structure. */ static AUTH_REQ *radrecv(UINT4 host, u_short udp_port, char *buffer, int length) { char *ptr; AUTH_HDR *auth; int totallen; int attribute; int attrlen; DICT_ATTR *attr; UINT4 lvalue; VALUE_PAIR *first_pair; VALUE_PAIR *prev; VALUE_PAIR *pair; AUTH_REQ *authreq; /* * Pre-allocate the new request data structure */ if((authreq = (AUTH_REQ *)malloc(sizeof(AUTH_REQ))) == (AUTH_REQ *)NULL) { fprintf(stderr, "%s: no memory\n", progname); exit(1); } auth = (AUTH_HDR *)buffer; totallen = ntohs(auth->length); printf("radrecv: Request from host %lx code=%d, id=%d, length=%d\n", (u_long)host, auth->code, auth->id, totallen); /* * Fill header fields */ authreq->ipaddr = host; authreq->udp_port = udp_port; authreq->id = auth->id; authreq->code = auth->code; memcpy(authreq->vector, auth->vector, AUTH_VECTOR_LEN); /* * Extract attribute-value pairs */ ptr = auth->data; length -= AUTH_HDR_LEN; first_pair = (VALUE_PAIR *)NULL; prev = (VALUE_PAIR *)NULL; while(length > 0) { attribute = *ptr++; attrlen = *ptr++; if(attrlen < 2) { length = 0; continue; } attrlen -= 2; if((attr = dict_attrget(attribute)) == (DICT_ATTR *)NULL) { printf("Received unknown attribute %d\n", attribute); } else if ( attrlen >= AUTH_STRING_LEN ) { printf("attribute %d too long, %d >= %d\n", attribute, attrlen, AUTH_STRING_LEN); } else { if((pair = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == (VALUE_PAIR *)NULL) { fprintf(stderr, "%s: no memory\n", progname); exit(1); } strcpy(pair->name, attr->name); pair->attribute = attr->value; pair->type = attr->type; pair->next = (VALUE_PAIR *)NULL; switch(attr->type) { case PW_TYPE_STRING: memcpy(pair->strvalue, ptr, attrlen); pair->strvalue[attrlen] = '\0'; if(first_pair == (VALUE_PAIR *)NULL) { first_pair = pair; } else { prev->next = pair; } prev = pair; break; case PW_TYPE_INTEGER: case PW_TYPE_IPADDR: memcpy(&lvalue, ptr, sizeof(UINT4)); pair->lvalue = ntohl(lvalue); if(first_pair == (VALUE_PAIR *)NULL) { first_pair = pair; } else { prev->next = pair; } prev = pair; break; default: printf(" %s (Unknown Type %d)\n", attr->name,attr->type); free(pair); break; } } ptr += attrlen; length -= attrlen + 2; } authreq->request = first_pair; return(authreq); } /* * Receive and print the result. */ int result_recv(UINT4 host, u_short udp_port, char *buffer, int length) { AUTH_HDR *auth; int totallen; char reply_digest[AUTH_VECTOR_LEN]; char calc_digest[AUTH_VECTOR_LEN]; int secretlen; AUTH_REQ *authreq; VALUE_PAIR *req; auth = (AUTH_HDR *)buffer; totallen = ntohs(auth->length); if(totallen != length) { printf("Received invalid reply length from server (want %d/ got %d)\n", totallen, length); exit(1); } /* Verify the reply digest */ memcpy(reply_digest, auth->vector, AUTH_VECTOR_LEN); memcpy(auth->vector, vector, AUTH_VECTOR_LEN); secretlen = strlen(secretkey); memcpy(buffer + length, secretkey, secretlen); md5_calc(calc_digest, (char *)auth, length + secretlen); if(memcmp(reply_digest, calc_digest, AUTH_VECTOR_LEN) != 0) { printf("Warning: Received invalid reply digest from server\n"); } authreq = radrecv(host, udp_port, buffer, length); req = authreq->request; while(req) { printf(" "); fprint_attr_val(stdout, req); printf("\n"); req = req->next; } if(auth->code != PW_AUTHENTICATION_ACK) { printf("Access denied.\n"); return -1; } return 0; } /* * Print usage message and exit. */ void usage(void) { fprintf(stderr, "Usage: %s username passwd servername portno secretkey [ppphint] [nasname]\n", progname); exit(1); } /* * Generate a random vector. */ static void random_vector(char *vector) { int randno; int i; srand(time(0)); for(i = 0;i < AUTH_VECTOR_LEN;) { randno = rand(); memcpy(vector, &randno, sizeof(int)); vector += sizeof(int); i += sizeof(int); } } int main(int argc, char **argv) { int salen; int result; struct sockaddr salocal; struct sockaddr saremote; struct sockaddr_in *sin; struct servent *svp; u_short svc_port; AUTH_HDR *auth; char *username; char *passwd; char *server; char passbuf[AUTH_PASS_LEN]; char md5buf[256]; char nasname[256]; UINT4 nas_ipaddr; UINT4 auth_ipaddr; u_short local_port; int total_length; int portno; int ppphint = 0; char *ptr; int length; int secretlen; int i; progname = argv[0]; if (argc < 6 || argc > 8) { usage(); } username = argv[1]; passwd = argv[2]; server = argv[3]; secretkey = argv[5]; ptr = argv[4]; if (*ptr == 's' || *ptr == 'S') ptr++; portno = atoi(ptr); if (argc > 6) ppphint = atoi(argv[6]); if (argc > 7) strcpy(nasname, argv[7]); else gethostname(nasname, sizeof(nasname)); nas_ipaddr = get_ipaddr(nasname); dict_init(NULL); /* * Open a connection to the server. */ svp = getservbyname ("radius", "udp"); if (svp == (struct servent *) 0) svc_port = 1645; else svc_port = ntohs((u_short) svp->s_port); /* Get the IP address of the authentication server */ if((auth_ipaddr = get_ipaddr(server)) == 0) { fprintf(stderr, "Couldn't find host %s\n", server); exit(1); } sockfd = socket (AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror ("socket"); exit(1); } sin = (struct sockaddr_in *) &salocal; memset (sin, 0, sizeof (salocal)); sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; local_port = 1025; do { local_port++; sin->sin_port = htons((u_short)local_port); } while((bind(sockfd, &salocal, sizeof (struct sockaddr_in)) < 0) && local_port < 64000); if(local_port >= 64000) { close(sockfd); perror ("bind"); exit(1); } /* * Build an authentication request */ auth = (AUTH_HDR *)send_buffer; auth->code = PW_AUTHENTICATION_REQUEST; auth->id = 25; random_vector(vector); memcpy(auth->vector, vector, AUTH_VECTOR_LEN); total_length = AUTH_HDR_LEN; ptr = auth->data; /* * User Name */ *ptr++ = PW_USER_NAME; length = strlen(username); if(length > MAXPWNAM) { length = MAXPWNAM; } *ptr++ = length + 2; memcpy(ptr, username, length); ptr += length; total_length += length + 2; /* * Password */ *ptr++ = PW_PASSWORD; *ptr++ = AUTH_PASS_LEN + 2; length = strlen(passwd); if(length > MAXPASS) { length = MAXPASS; } memset(passbuf, 0, AUTH_PASS_LEN); memcpy(passbuf, passwd, length); /* Calculate the MD5 Digest */ secretlen = strlen(secretkey); strcpy(md5buf, secretkey); memcpy(md5buf + secretlen, auth->vector, AUTH_VECTOR_LEN); md5_calc(ptr, md5buf, secretlen + AUTH_VECTOR_LEN); /* Xor the password into the MD5 digest */ for(i = 0;i < AUTH_PASS_LEN;i++) *ptr++ ^= passbuf[i]; total_length += AUTH_PASS_LEN + 2; *ptr++ = PW_CLIENT_PORT_ID; *ptr++ = 6; *(UINT4 *)ptr = htonl(portno); ptr += 4; total_length += 6; *ptr++ = PW_CLIENT_ID; *ptr++ = 6; *(UINT4 *)ptr = htonl(nas_ipaddr); ptr += 4; total_length += 6; /* * We might need to add a PPP hint. */ if (ppphint) { *ptr++ = PW_FRAMED_PROTOCOL; *ptr++ = 6; *(UINT4 *)ptr = htonl(PW_PPP); ptr += 4; total_length += 6; } auth->length = htons(total_length); /* * Send the request we've built. */ sin = (struct sockaddr_in *) &saremote; memset (sin, 0, sizeof (saremote)); sin->sin_family = AF_INET; sin->sin_addr.s_addr = htonl(auth_ipaddr); sin->sin_port = htons(svc_port); sendto(sockfd, (char *)auth, total_length, 0, &saremote, sizeof(struct sockaddr_in)); salen = sizeof (saremote); result = recvfrom (sockfd, recv_buffer, sizeof(recv_buffer), 0, &saremote, &salen); if (result > 0) { result_recv(sin->sin_addr.s_addr, sin->sin_port, recv_buffer, result); exit(0); } perror ("recv"); close(sockfd); exit(1); }