Back to index

nagios-plugins  1.4.16
radtest.c
Go to the documentation of this file.
00001 /*
00002  *
00003  *     RADIUS
00004  *     Remote Authentication Dial In User Service
00005  *
00006  *
00007  *     Livingston Enterprises, Inc.
00008  *     6920 Koll Center Parkway
00009  *     Pleasanton, CA   94566
00010  *
00011  *     Copyright 1992 Livingston Enterprises, Inc.
00012  *
00013  *     Permission to use, copy, modify, and distribute this software for any
00014  *     purpose and without fee is hereby granted, provided that this
00015  *     copyright and permission notice appear on all copies and supporting
00016  *     documentation, the name of Livingston Enterprises, Inc. not be used
00017  *     in advertising or publicity pertaining to distribution of the
00018  *     program without specific prior permission, and notice be given
00019  *     in supporting documentation that copying and distribution is by
00020  *     permission of Livingston Enterprises, Inc.   
00021  *
00022  *     Livingston Enterprises, Inc. makes no representations about
00023  *     the suitability of this software for any purpose.  It is
00024  *     provided "as is" without express or implied warranty.
00025  *
00026  */
00027 
00028 char radtest_sccsid[] =
00029 "@(#)radpass.c       1.5 Copyright 1992 Livingston Enterprises Inc\n"
00030 "@(#)radtest.c       1.3 Copyright 1999 Cistron Internet Services B.V.";
00031 
00032 #include      <sys/types.h>
00033 #include      <sys/socket.h>
00034 #include      <sys/time.h>
00035 #include      <netinet/in.h>
00036 
00037 #include      <stdio.h>
00038 #include      <unistd.h>
00039 #include      <netdb.h>
00040 #include      <pwd.h>
00041 #include      <stdlib.h>
00042 #include      <errno.h>
00043 
00044 #include      "radiusd.h"
00045 #include      "conf.h"
00046 
00047 #define MAXPWNAM     32
00048 #define MAXPASS             16
00049 
00050 #define TEST_VENDOR  1
00051 #define TEST_USR     1
00052 
00053 int           i_send_buffer[2048];
00054 int           i_recv_buffer[2048];
00055 char          *send_buffer = (char *)i_send_buffer;
00056 char          *recv_buffer = (char *)i_recv_buffer;
00057 
00058 char          *progname;
00059 int           sockfd;
00060 char          vector[AUTH_VECTOR_LEN];
00061 char          *secretkey;
00062 
00063 char          *radius_dir = RADIUS_DIR;
00064 char          *radlog_dir = NULL;
00065 int           debug_flag = 0;
00066 
00067 /*
00068  *     Receive UDP client requests, build an authorization request
00069  *     structure, and attach attribute-value pairs contained in
00070  *     the request to the new structure.
00071  */
00072 static AUTH_REQ      *test_radrecv(UINT4 host, u_short udp_port,
00073                      char *buffer, int length)
00074 {
00075        u_char        *ptr;
00076        AUTH_HDR      *auth;
00077        int           totallen;
00078        int           attribute;
00079        int           attrlen;
00080        DICT_ATTR     *attr;
00081        UINT4         lvalue;
00082        VALUE_PAIR    *first_pair;
00083        VALUE_PAIR    *prev;
00084        VALUE_PAIR    *pair;
00085        AUTH_REQ      *authreq;
00086 
00087        /*
00088         *     Pre-allocate the new request data structure
00089         */
00090 
00091        if((authreq = (AUTH_REQ *)malloc(sizeof(AUTH_REQ))) ==
00092                                           (AUTH_REQ *)NULL) {
00093               fprintf(stderr, "%s: no memory\n", progname);
00094               exit(1);
00095        }
00096 
00097        auth = (AUTH_HDR *)buffer;
00098        totallen = ntohs(auth->length);
00099 
00100        printf("radrecv: Reply from host %lx code=%d, id=%d, length=%d\n",
00101                             (u_long)host, auth->code, auth->id, totallen);
00102 
00103        /*
00104         *     Fill header fields
00105         */
00106        authreq->ipaddr = host;
00107        authreq->udp_port = udp_port;
00108        authreq->id = auth->id;
00109        authreq->code = auth->code;
00110        memcpy(authreq->vector, auth->vector, AUTH_VECTOR_LEN);
00111 
00112        /*
00113         *     Extract attribute-value pairs
00114         */
00115        ptr = (u_char *)auth->data;
00116        length -= AUTH_HDR_LEN;
00117        first_pair = (VALUE_PAIR *)NULL;
00118        prev = (VALUE_PAIR *)NULL;
00119 
00120        while(length > 0) {
00121 
00122               attribute = *ptr++;
00123               attrlen = *ptr++;
00124               if(attrlen < 2) {
00125                      length = 0;
00126                      continue;
00127               }
00128               attrlen -= 2;
00129               if((attr = dict_attrget(attribute)) == (DICT_ATTR *)NULL) {
00130                      printf("Received unknown attribute %d\n", attribute);
00131               }
00132               else if ( attrlen >= AUTH_STRING_LEN ) {
00133                      printf("attribute %d too long, %d >= %d\n", attribute,
00134                             attrlen, AUTH_STRING_LEN);
00135               }
00136               else {
00137                      if((pair = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) ==
00138                                           (VALUE_PAIR *)NULL) {
00139                             fprintf(stderr, "%s: no memory\n",
00140                                           progname);
00141                             exit(1);
00142                      }
00143                      /* Same size */
00144                      strcpy(pair->name, attr->name);
00145                      pair->attribute = attr->value;
00146                      pair->type = attr->type;
00147                      pair->next = (VALUE_PAIR *)NULL;
00148 
00149                      switch(attr->type) {
00150 
00151                      case PW_TYPE_STRING:
00152                             memcpy(pair->strvalue, ptr, attrlen);
00153                             pair->strvalue[attrlen] = '\0';
00154                             pair->length = attrlen;
00155                             if(first_pair == (VALUE_PAIR *)NULL) {
00156                                    first_pair = pair;
00157                             }
00158                             else {
00159                                    prev->next = pair;
00160                             }
00161                             prev = pair;
00162                             break;
00163                      
00164                      case PW_TYPE_INTEGER:
00165                      case PW_TYPE_IPADDR:
00166                             memcpy(&lvalue, ptr, sizeof(UINT4));
00167                             pair->lvalue = ntohl(lvalue);
00168                             if(first_pair == (VALUE_PAIR *)NULL) {
00169                                    first_pair = pair;
00170                             }
00171                             else {
00172                                    prev->next = pair;
00173                             }
00174                             prev = pair;
00175                             break;
00176                      
00177                      default:
00178                             printf("    %s (Unknown Type %d)\n", attr->name,attr->type);
00179                             free(pair);
00180                             break;
00181                      }
00182 
00183               }
00184               ptr += attrlen;
00185               length -= attrlen + 2;
00186        }
00187        authreq->request = first_pair;
00188        return(authreq);
00189 }
00190 
00191 
00192 /*
00193  *     Receive and print the result.
00194  */
00195 int result_recv(UINT4 host, u_short udp_port, char *buffer, int length)
00196 {
00197        AUTH_HDR      *auth;
00198        int           totallen;
00199        char          reply_digest[AUTH_VECTOR_LEN];
00200        char          calc_digest[AUTH_VECTOR_LEN];
00201        int           secretlen;
00202        AUTH_REQ      *authreq;
00203        VALUE_PAIR    *req;
00204 
00205        auth = (AUTH_HDR *)buffer;
00206        totallen = ntohs(auth->length);
00207 
00208        if(totallen != length) {
00209               printf("Received invalid reply length from server (want %d/ got %d)\n", totallen, length);
00210               exit(1);
00211        }
00212 
00213        /* Verify the reply digest */
00214        memcpy(reply_digest, auth->vector, AUTH_VECTOR_LEN);
00215        memcpy(auth->vector, vector, AUTH_VECTOR_LEN);
00216        secretlen = strlen(secretkey);
00217        memcpy(buffer + length, secretkey, secretlen);
00218        md5_calc(calc_digest, (char *)auth, length + secretlen);
00219 
00220        if(memcmp(reply_digest, calc_digest, AUTH_VECTOR_LEN) != 0) {
00221               printf("Warning: Received invalid reply digest from server\n");
00222        }
00223 
00224        authreq = test_radrecv(host, udp_port, buffer, length);
00225 
00226        req = authreq->request;
00227 
00228        while(req) {
00229               printf("    ");
00230               fprint_attr_val(stdout, req);
00231               printf("\n");
00232               req = req->next;
00233        }
00234        if(auth->code != PW_AUTHENTICATION_ACK) {
00235               printf("Access denied.\n");
00236               return -1;
00237        }
00238        return 0;
00239 }
00240 
00241 
00242 
00243 
00244 /*
00245  *     Print usage message and exit.
00246  */
00247 void usage(void)
00248 {
00249        fprintf(stderr, "Usage: %s username passwd servername nas_port_id secretkey [ppphint] [nasname]\n",
00250               progname);
00251        exit(1);
00252 }
00253 
00254 
00255 /*
00256  *     Generate a random vector.
00257  */
00258 static void random_vector(char *vector)
00259 {
00260        int    randno;
00261        int    i;
00262 
00263        srand(time(0));
00264        for(i = 0;i < AUTH_VECTOR_LEN;) {
00265               randno = rand();
00266               memcpy(vector, &randno, sizeof(int));
00267               vector += sizeof(int);
00268               i += sizeof(int);
00269        }
00270 }
00271 
00272 
00273 int main(int argc, char **argv)
00274 {
00275        int                  salen;
00276        int                  result;
00277        struct sockaddr      salocal;
00278        struct sockaddr      saremote;
00279        struct sockaddr_in   *sin;
00280        struct servent              *svp;
00281        struct timeval              tv;
00282        fd_set               readfds;
00283         u_short                 svc_port;
00284        AUTH_HDR             *auth;
00285        char                 *username;
00286        char                 *passwd;
00287        char                 *server;
00288        char                 passbuf[AUTH_PASS_LEN];
00289        char                 md5buf[256];
00290        char                 nasname[256];
00291        UINT4                nas_ipaddr;
00292        UINT4                auth_ipaddr;
00293        UINT4                ui;
00294        u_short                     local_port;
00295        u_short                     total_length;
00296        int                  portno;
00297        int                  ppphint = 0;
00298        char                 *ptr;
00299        int                  length;
00300        int                  secretlen;
00301        int                  i;
00302        int                  bogus_packet = 0;
00303 
00304        progname = argv[0];
00305 
00306        if (argv[1] && strcmp(argv[1], "-b") == 0) {
00307               argv++;
00308               argc--;
00309               bogus_packet = 1;
00310        }
00311 
00312        if (argc < 6 || argc > 8) {
00313               usage();
00314        }
00315        username  = argv[1];
00316        passwd    = argv[2];
00317        server    = argv[3];
00318        secretkey = argv[5];
00319        ptr = argv[4];
00320        if (*ptr == 's' || *ptr == 'S') ptr++;
00321        portno = atoi(ptr);
00322        if (argc > 6) ppphint = atoi(argv[6]);
00323 
00324        if (argc > 7)
00325               strNcpy(nasname, argv[7], sizeof(nasname));
00326        else
00327               gethostname(nasname, sizeof(nasname));
00328        nas_ipaddr = get_ipaddr(nasname);
00329 
00330        dict_init(NULL);
00331 
00332        /*
00333         *     Open a connection to the server.
00334         */
00335        svp = getservbyname ("radius", "udp");
00336        if (svp == (struct servent *) 0)
00337               svc_port = PW_AUTH_UDP_PORT;
00338        else
00339               svc_port = ntohs((u_short) svp->s_port);
00340 
00341        /* Get the IP address of the authentication server */
00342        if((auth_ipaddr = get_ipaddr(server)) == 0) {
00343               fprintf(stderr, "Couldn't find host %s\n", server);
00344               exit(1);
00345        }
00346 
00347        sockfd = socket (AF_INET, SOCK_DGRAM, 0);
00348        if (sockfd < 0) {
00349               perror ("socket");
00350               exit(1);
00351        }
00352 
00353        sin = (struct sockaddr_in *) &salocal;
00354         memset (sin, 0, sizeof (salocal));
00355        sin->sin_family = AF_INET;
00356        sin->sin_addr.s_addr = INADDR_ANY;
00357 
00358        local_port = 1025;
00359        do {
00360               local_port++;
00361               sin->sin_port = htons((u_short)local_port);
00362        } while((bind(sockfd, &salocal, sizeof (struct sockaddr_in)) < 0) &&
00363                                           local_port < 64000);
00364        if (local_port >= 64000) {
00365               close(sockfd);
00366               perror ("bind");
00367               exit(1);
00368        }
00369 
00370        /*
00371         *     Build an authentication request
00372         */
00373        auth = (AUTH_HDR *)send_buffer;
00374        auth->code = PW_AUTHENTICATION_REQUEST;
00375        auth->id = getpid() % 256;
00376        random_vector(vector);
00377        memcpy(auth->vector, vector, AUTH_VECTOR_LEN);
00378        total_length = AUTH_HDR_LEN;
00379        ptr = auth->data;
00380 
00381        /*
00382         *     User Name
00383         */
00384        *ptr++ = PW_USER_NAME;
00385        length = strlen(username);
00386        if(length > MAXPWNAM) {
00387               length = MAXPWNAM;
00388        }
00389        *ptr++ = length + 2;
00390        memcpy(ptr, username, length);
00391        ptr += length;
00392        total_length += length + 2;
00393 
00394        /*
00395         *     Password
00396         */
00397        *ptr++ = PW_PASSWORD;
00398        *ptr++ = AUTH_PASS_LEN + 2;
00399 
00400        length = strlen(passwd);
00401        if(length > MAXPASS) {
00402               length = MAXPASS;
00403        }
00404        memset(passbuf, 0, AUTH_PASS_LEN);
00405        memcpy(passbuf, passwd, length);
00406 
00407        /* Calculate the MD5 Digest */
00408        secretlen = strlen(secretkey);
00409        strNcpy(md5buf, secretkey, sizeof(md5buf));
00410        memcpy(md5buf + secretlen, auth->vector, AUTH_VECTOR_LEN);
00411        md5_calc(ptr, md5buf, secretlen + AUTH_VECTOR_LEN);
00412 
00413        /* Xor the password into the MD5 digest */
00414        for(i = 0;i < AUTH_PASS_LEN;i++) {
00415               *ptr++ ^= passbuf[i];
00416        }
00417        total_length += AUTH_PASS_LEN + 2;
00418 
00419        *ptr++ = PW_NAS_PORT_ID;
00420        *ptr++ = 6;
00421        ui = htonl(portno);
00422        memcpy(ptr, &ui, sizeof(UINT4));
00423        ptr += 4;
00424        total_length += 6;
00425 
00426 #if TEST_VENDOR
00427        *ptr++ = PW_VENDOR_SPECIFIC;
00428        *ptr++ = 18;
00429        ui = htonl(307); /* livingston */
00430        memcpy(ptr, &ui, sizeof(UINT4));
00431        ptr += 4;
00432 
00433        *ptr++ = 2; /* LE-Terminate-Detail */
00434        *ptr++ = 6; /* len */
00435        strcpy(ptr, "test");
00436        ptr += 4;
00437 
00438        *ptr++ = 3; /* LE-Advice-of-Charge */
00439        *ptr++ = 6; /* len */
00440        strcpy(ptr, "TiNC");
00441        ptr += 4;
00442 
00443        total_length += 18;
00444 #endif
00445 
00446 #if TEST_USR
00447        *ptr++ = PW_VENDOR_SPECIFIC;
00448        *ptr++ = 14;
00449        ui = htonl(429); /* USR */
00450        memcpy(ptr, &ui, sizeof(UINT4));
00451        ptr += 4;
00452        ui = htonl(0x9823); /* Terminal-Type */
00453        memcpy(ptr, &ui, sizeof(UINT4));
00454        ptr += 4;
00455        strcpy(ptr, "test");
00456        ptr += 4;
00457        total_length += 14;
00458 #endif
00459 
00460        *ptr++ = PW_NAS_IP_ADDRESS;
00461        *ptr++ = 6;
00462        ui = htonl(nas_ipaddr);
00463        memcpy(ptr, &ui, sizeof(UINT4));
00464        ptr += 4;
00465        total_length += 6;
00466 
00467        /*
00468         *     We might need to add a PPP hint.
00469         */
00470        if (ppphint) {
00471               *ptr++ = PW_FRAMED_PROTOCOL;
00472               *ptr++ = 6;
00473               ui = htonl(PW_PPP);
00474               memcpy(ptr, &ui, sizeof(UINT4));
00475               ptr += 4;
00476               total_length += 6;
00477        }
00478 
00479        if (bogus_packet) {
00480               *ptr++ = PW_FILTER_ID;
00481               length = 4096;
00482               *ptr++ = length + 2;
00483               for(i = 0; i < 4096; i++)
00484                      *ptr++ = 'A';
00485               ptr += length;
00486               total_length += length + 2;
00487        }
00488 
00489        auth->length = htons(total_length);
00490 
00491        /*
00492         *     Send the request we've built.
00493         */
00494        sin = (struct sockaddr_in *) &saremote;
00495         memset (sin, 0, sizeof (saremote));
00496        sin->sin_family = AF_INET;
00497        sin->sin_addr.s_addr = htonl(auth_ipaddr);
00498        sin->sin_port = htons(svc_port);
00499 
00500        printf("Sending request.\n");
00501        for (i = 0; i < 10; i++) {
00502               if (i > 0) printf("Re-sending request.\n");
00503               sendto(sockfd, (char *)auth, total_length, 0,
00504                      &saremote, sizeof(struct sockaddr_in));
00505 
00506               tv.tv_sec = 3;
00507               tv.tv_usec = 0;
00508               FD_ZERO(&readfds);
00509               FD_SET(sockfd, &readfds);
00510               if (select(sockfd + 1, &readfds, NULL, NULL, &tv) == 0)
00511                      continue;
00512               salen = sizeof (saremote);
00513               result = recvfrom (sockfd, recv_buffer, sizeof(i_recv_buffer),
00514                      0, &saremote, &salen);
00515               if (result >= 0)
00516                      break;
00517               sleep(tv.tv_sec);
00518        }
00519        if (result > 0 && i < 10) {
00520               result_recv(sin->sin_addr.s_addr,
00521                                    sin->sin_port, recv_buffer, result);
00522               exit(0);
00523        }
00524        printf("No answer.\n");
00525        close(sockfd);
00526        exit(1);
00527 }