#ifndef NORADIUS
/* 
        DEFINE printf - imsg 
        This module implements these funcitions 
        int rad_lookup(char *user, char *pass, char *host, char *seckey, int ecode, char *extra);

  host = radius host
  seckey = secret key defined on radius host (password basically)
  ecode = numeric code for extra data, e.g. 26 = vendor specified.  
  extra must be 1000 bytes or bigger., receives ecode data, e.g. usergroups.

*/

int rad_lookup(char *user, char *pass, char *host, char *seckey, int ecode, char *extra);
int rad_send(char *bf, int total_length);
int rad_read(char *bf);

#include "conf.h"
#ifdef WIN32
#include <winsock.h>
#include <process.h>
#define socket_close closesocket
#define DONE_TCP TRUE
#endif

#ifdef OS2
#define INVALID_SOCKET -1
typedef int SOCKET;
#define DONE_TCP TRUE
#define BSD_SELECT   TRUE
#include <errno.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netdb.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <nerrno.h>
#include <utils.h>
#undef SOCKET_DEF
#define socket_ioctl ioctl
#define socket_read(s,b,l) recv(s,b,l,0)
#define socket_write(s,b,l) send(s,b,l,0)
#define socket_close(s) soclose(s)
#endif


#ifndef DONE_TCP
#define INVALID_SOCKET -1
#include        <sys/types.h>
#include        <sys/socket.h>
#include        <sys/time.h>
#include        <netinet/in.h>
#include        <netdb.h>
#include        <pwd.h>
#include        <unistd.h>
#include        <errno.h>
#define socket_close close
#define socket_open open
#define socket_read read
#define socket_ioctl ioctl
#define socket_write write

typedef int SOCKET;

#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE (!0)
#endif



#include        <stdio.h>
#include        <stdlib.h>
#include        <errno.h>
#include        <time.h>


#ifdef OS2
typedef unsigned char u_char;
typedef unsigned short u_short;
#endif

#include "md5.h"
#include        "radius.h"

#define MAXPWNAM        32
#define MAXPASS         16


char *rad_tcp_error(void);
void rad_tcp_last(void);
int good_ipaddr(char *addr);
DICT_ATTR *dict_attrget(int attribute);
void md5_calc(unsigned char *output, unsigned char *input, unsigned int inlen);
int imsg(const char *arg_list, ...);
#include "lprintf.h"

#define printf imsg

/*#define TESTING 1 */
#ifdef TESTING
void tcp_startup(void)
{
        WORD wVersionRequested;
        WSADATA wsaData;
        int err;
        wVersionRequested = MAKEWORD( 1, 1 );

        err = WSAStartup( wVersionRequested, &wsaData );
        if ( err != 0 ) { printf("No winsock found of correct version\n"); return;}
        if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) {
                printf("No winsock found of correct version, trying to continue\n");
                goto ret;
        }
ret: ;
  
}


int main(int argc, char **argv)
{
        int r;
        char extra[1000];
        if (argc<3) {
                printf("Usage: user pass host key\n");
                return 0;
        }
        tcp_startup();
        r = rad_lookup(argv[1],argv[2],argv[3],argv[4],26,extra);
        if (r) printf("Lookup worked %s\n",extra);
        else printf("lookup failed\n");
}
#endif

UINT4 get_ipaddr(char *host)
{
        struct hostent  *hp;
        UINT4           ipstr2long();

        if(good_ipaddr(host) == 0) {
                return(ipstr2long(host));
        }
        else if((hp = gethostbyname(host)) == (struct hostent *)NULL) {
                return((UINT4)0);
        }
        return(ntohl(*(UINT4 *)hp->h_addr));
}
static AUTH_REQ *rad_radrecv(char *buffer, int length);
static char send_buffer[2048*sizeof(int)];
static char recv_buffer[2048*sizeof(int)];
static int store_id;

void rad_tcp_last(void);
char *rad_tcp_error(void);
static  UINT4 auth_ipaddr;
static SOCKET sockfd;
static struct sockaddr saremote;
static int svc_port;
static char nasname[256];
static int local_port;
#define BFSZ 1000

int rad_open(char *xserver,int isacct)
{
	int i;
	char server[BFSZ];
	char *s;
        struct  sockaddr_in *sin;
        static struct sockaddr salocal;
        struct  servent *svp;
        /*
         *      Open a connection to the server.
         */

	strncpy(server,xserver,200);
	if(isacct) { /* RL */
		svp = getservbyname ("radacct", "udp");
		if (svp == (struct servent *) 0) svc_port = PW_ACCT_UDP_PORT;
		else svc_port = ntohs((u_short) svp->s_port);
		
		i = atoi(config_get(C_RADIUS_ACCT_PORT));
		if(i) svc_port=i;
	} else {
		svp = getservbyname ("radius", "udp");
		if (svp == (struct servent *) 0) svc_port = PW_AUTH_UDP_PORT;
		else svc_port = ntohs((u_short) svp->s_port);
	}

	s = strchr(server,':');
	if (s!=NULL) {
		*s = 0;
		if(!isacct) svc_port = atoi(s+1);
	}

        /* Get the IP address of the authentication server */
        if((auth_ipaddr = get_ipaddr(server)) == 0) { printf("radius: Couldn't find host %s", server); return FALSE;    }

        sockfd = socket (AF_INET, SOCK_DGRAM, 0); rad_tcp_last();
        if (sockfd ==INVALID_SOCKET) {printf("radius: socket() %s",rad_tcp_error()); return FALSE; }

        sin = (struct sockaddr_in *) &salocal;
        memset (sin, 0, sizeof (salocal));
        sin->sin_family = AF_INET;
		
		
		s=config_get(C_RADIUS_BIND_OUT);
        if(*s) sin->sin_addr.s_addr = inet_addr(s);
		else sin->sin_addr.s_addr = INADDR_ANY;
        sin->sin_port = 0;


        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 (bind(sockfd, &salocal, sizeof (struct sockaddr_in)) !=0) {
                rad_tcp_last();
                printf("bind() %s",rad_tcp_error()); return FALSE; 
        }
        */
        return TRUE;

} 

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);
        }
}

static char vector[AUTH_VECTOR_LEN];
static UINT4 nas_ipaddr;
static char secretkey[1000];

int rad_acct(char *user,int nbytes,char *host,char *seckey,int chanid,int type) /* type=PW_STATUS_START OR PW_STATUS_STOP ONLY */
{
	char packet[5000];
	char authen[16];
	static char id=0,identifier;
	short length=38,nslen;
	int seckeylen,r,i,l;
	char *s;

	if(!rad_open(host,1)) return FALSE; 

	*packet=PW_ACCOUNTING_REQUEST;
	*(packet+1)=identifier=getpid()+id++%256;

	/* Reserve
		2 byte length
		16 byte authenticator
	*/

	/* Attributes... length already includes these! */
	*(packet+20)=PW_ACCT_STATUS_TYPE;
	*(packet+21)=6;
	*((long *)(packet+22))=htonl(type);

	*(packet+26)=PW_ACCT_SESSION_ID;
	*(packet+27)=6;
	*((long *)(packet+28))=htonl(chanid);

	*(packet+32)=PW_NAS_IP_ADDRESS;
	*(packet+33)=6;
	s=config_get(C_RADIUS_BIND_OUT);
	if(*s) nas_ipaddr = get_ipaddr(s);
	else nas_ipaddr = get_ipaddr(nasname);
	*((long *)(packet+34))=htonl(nas_ipaddr);

	if(type==PW_STATUS_STOP) {
		/* Optional attributes below */
		length+=6;
		*(packet+38)=PW_ACCT_OUTPUT_OCTETS;
		*(packet+39)=6;
		*((long *)(packet+40))=htonl(nbytes);

		if(l=strlen(user)) {
			*(packet+44)=PW_USER_NAME;
			length+=(*(packet+45)=l+2);
			memcpy(packet+46,user,l);
		}
	}

	/* Add length */
	nslen=htons(length);
	memcpy(packet+2,&nslen,2);

	/* Add shared secret (for authenticator calculation only, not sent) */
	seckeylen=strlen(seckey);
	if(seckeylen+length>5000) return FALSE;
	memcpy(packet+length,seckey,strlen(seckey));

	/* Calculate autheticator */
	memset(packet+4,0,16);
	md5_calc(authen,packet,seckeylen+length);

	/* Add authenticator */
	memcpy(packet+4,authen,16);

	for (i=0; i<5; i++) {
		if (i) printf("radius: Accounting start retry %d (%s:%d)\n",i,host,svc_port);
		r=rad_send(packet,length);
		if (r<=0) return FALSE;
		r = rad_read(recv_buffer);
                if (r>0) {
                        if(recv_buffer[0]==PW_ACCOUNTING_RESPONSE && recv_buffer[1]==identifier) {
				socket_close(sockfd);
				return TRUE;
			}
                }
        }
	
        socket_close(sockfd);
	return FALSE;
}

char *rad_request(char *username, char *passwd, char *xsecretkey, int *rlen)
{
        AUTH_HDR *auth;
        u_char *ptr;
        static int idbase;
        int total_length;
        int length;
        char passbuf[AUTH_PASS_LEN];
        char md5buf[256];
        char nasname[256];
        int secretlen;
        int i;
        int ui;
		char *s;

        strcpy(secretkey,xsecretkey);
        auth = (AUTH_HDR *)send_buffer;
        auth->code = PW_AUTHENTICATION_REQUEST;
        auth->id = getpid()+idbase++ % 256 ;
        store_id = auth->id;
        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_NAS_PORT_ID;
        *ptr++ = 6;
        ui = htonl(svc_port);
        memcpy(ptr, &ui, sizeof(UINT4));
        ptr += 4;
        total_length += 6;

		s=config_get(C_RADIUS_BIND_OUT);
		if(*s) nas_ipaddr = get_ipaddr(s);
		else {
			gethostname(nasname, sizeof(nasname));
			nas_ipaddr = get_ipaddr(nasname);
		}
                
        *ptr++ = PW_NAS_IP_ADDRESS;
        *ptr++ = 6;
        ui = htonl(nas_ipaddr);
        memcpy(ptr, &ui, sizeof(UINT4));
        ptr += 4;
        total_length += 6;

        auth->length = htons((short) total_length);
        *rlen = total_length;
        return (char *) auth;
}
int rad_send(char *bf, int total_length)
{
        struct  sockaddr_in     *sin;
        int r;

        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((short) svc_port);

        r = sendto(sockfd, bf, total_length, 0,&saremote, sizeof(struct sockaddr_in));
        rad_tcp_last();
        if (r<=0) printf("radius: Sent %d bytes %s\n",r,rad_tcp_error());
        
        return r;
}
int rad_read(char *bf)
{
        int salen,result;
        struct timeval          tv;
        fd_set                  readfds;
        tv.tv_sec = 1;
        tv.tv_usec = 0;
        FD_ZERO(&readfds);
        FD_SET(sockfd, &readfds);
        if (select(sockfd + 1, &readfds, NULL, NULL, &tv) == 0) return 0;
        salen = sizeof (saremote);
        result = recvfrom (sockfd, bf, sizeof(recv_buffer),
                0, &saremote, &salen);
        rad_tcp_last();
        if (result<=0) printf("radius: only got %d bytes %s\n",result,rad_tcp_error());
        return result;
}
static char extra_info[2000];
static int extra_code=999999;
int rad_decode(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); return FALSE;        }

        /* 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 = rad_radrecv(buffer, length);
        if (authreq==NULL) return FALSE;
        req = authreq->request;
        if (auth->id!=store_id) return 3; /* Wrong id */
        if(auth->code != PW_AUTHENTICATION_ACK) {
                return FALSE;
        }
        return TRUE;
}
int token_split(char *s, char *p[], char *sep, int tmax);

int rad_lookup_one(char *user, char *pass, char *host, char *seckey, int ecode, char *extra);
int rad_lookup(char *user, char *pass, char *host, char *seckey, int ecode, char *extra)
{
	char *p[100];
	char lhost[BFSZ];
	int np;
	int i;
	int r;
	strncpy(lhost,host,BFSZ-1); /* RL - stop overwriting config setting */
	np = token_split(lhost,p,", ",10);
	for (i=0; i<np; i++) {
		r = rad_lookup_one(user,pass,p[i],seckey,ecode,extra);
		if (r) return r;
	}
	return r;
}
int rad_lookup_one(char *user, char *pass, char *host, char *seckey, int ecode, char *extra)
{
        int i;
        int reqlen;
        char *req;
        int r;
        if (!rad_open(host,0))  return FALSE;
        extra_code = ecode;
        strcpy(extra_info,"");
        req = rad_request(user,pass,seckey,&reqlen);

        for (i=0; i<5; i++) {
                if (i>0) printf("radius: Trying again %d\n",i);
                r = rad_send(req,reqlen);
                if (r<=0) return FALSE;
again:          r = rad_read(recv_buffer);
                if (r>0) {
                        r = rad_decode(recv_buffer, r);
                        if (r==3) {
                                printf("radius: Wrong id, read next one\n");
                                goto again; /* 3 = again*/
                        }
                        socket_close(sockfd);
                        strcpy(extra,extra_info);
                        return r;
                }
        }
        socket_close(sockfd);
        strcpy(extra,"");
        return FALSE;

}
static AUTH_REQ *rad_radrecv(char *buffer, int length)
{
        u_char          *ptr;
        AUTH_HDR        *auth;
        int             totallen;
        int             attribute;
        int             attrlen;
        DICT_ATTR       *attr;
        UINT4           lvalue;
        VALUE_PAIR      *pair;
        static VALUE_PAIR vpair;
        AUTH_REQ        *authreq;
        static AUTH_REQ authdata;
        /*
         *      Pre-allocate the new request data structure
         */

        authreq = &authdata;
        auth = (AUTH_HDR *)buffer;
        totallen = ntohs(auth->length);

        /*
         *      Fill header fields
         */
        authreq->ipaddr = 0; /* host */
        authreq->udp_port = 0; /*udp_port;*/
        authreq->id = auth->id;
        authreq->code = auth->code;
        memcpy(authreq->vector, auth->vector, AUTH_VECTOR_LEN);

        /*
         *      Extract attribute-value pairs
         */
        ptr = (u_char *)auth->data;
        length -= AUTH_HDR_LEN;

        while(length > 0) {
                attribute = *ptr++;
                attrlen = *ptr++;
                if(attrlen < 2) {
                        length = 0;
                        continue;
                }
                attrlen -= 2;
                if((attr = dict_attrget(attribute)) == (DICT_ATTR *)NULL) {
                        printf("radius: Received unknown attribute %d\n", attribute);
                }
                else if ( attrlen >= AUTH_STRING_LEN ) {
                        printf("radius: attribute %d too long, %d >= %d\n", attribute,
                                attrlen, AUTH_STRING_LEN);
                }
                else {
                        pair = &vpair;
                        memset(pair,0,sizeof(*pair));
                        strcpy(pair->name, attr->name);
                        pair->attribute = attr->value;
                        pair->type = attr->type;

                        switch(attr->type) {

                        case PW_TYPE_STRING:
				if(attribute==26 && config_true(C_RADIUS_VENDOR_ENCODED)) {
/*lprintf(ptr,BFSZ-1,"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",0,0,0,9,1,18,103,114,111,117,112,115,61,109,111,100,101,114,97,116,111,114);*/			
					if(attrlen<8) break;
					attrlen=(char)(*(ptr+5)-2);
					ptr+=6;

				}
				memcpy(pair->strvalue, ptr, attrlen);
                                pair->strvalue[attrlen] = '\0';
                                pair->length = attrlen;
                                /*printf("radius: Got pair %d (%s) (%s)\n",pair->attribute,attr->name,pair->strvalue);*/
                                if (pair->attribute==extra_code) { /* vendor specific */
                                        strncpy(extra_info,pair->strvalue,900); 
                                }

                                break;
                        
                        case PW_TYPE_INTEGER:
                        case PW_TYPE_IPADDR:
                                memcpy(&lvalue, ptr, sizeof(UINT4));
                                pair->lvalue = ntohl(lvalue);
                                break;
                        
                        default:
                                printf("radius:     %s (Unknown Type %d)\n", attr->name,attr->type);
                                break;
                        }

                }
                ptr += attrlen;
                length -= attrlen + 2;
        }
        authreq->request = NULL;
        return(authreq);
}
int good_ipaddr(char *addr)
{
        int     dot_count;
        int     digit_count;

        dot_count = 0;
        digit_count = 0;
        while(*addr != '\0' && *addr != ' ') {
                if(*addr == '.') {
                        dot_count++;
                        digit_count = 0;
                }
                else if(!isdigit(*addr)) {
                        dot_count = 5;
                }
                else {
                        digit_count++;
                        if(digit_count > 3) {
                                dot_count = 5;
                        }
                }
                addr++;
        }
        if(dot_count != 3) {
                return(-1);
        }
        else {
                return(0);
        }
}
static int werrno;
#ifdef WIN32
void rad_tcp_last(void)
{
        werrno = WSAGetLastError();
}
char *rad_tcp_error(void)
{
        static char bf[500];
        char *s="";
        int err = werrno;
        if (err==WSANOTINITIALISED) lprintf(bf,500-1,"(%s) A successful WSAStartup must occur before using this API.\n",s);
        else if (err==WSAENETDOWN)      lprintf(bf,500-1,"(%s) The Windows Sockets implementation has detected that the network subsystem has failed.\n",s);
        else if (err==WSAEACCES)        lprintf(bf,500-1,"(%s) The requested address is a broadcast address, but the appropriate flag was not set.\n",s);
        else if (err==WSAEINTR) lprintf(bf,500-1,"(%s) The (blocking) call was cancelled via WSACancelBlockingCall.\n",s);
        else if (err==WSAEINPROGRESS)   lprintf(bf,500-1,"(%s) A blocking Windows Sockets operation is in progress.\n",s);
        else if (err==WSAEFAULT)        lprintf(bf,500-1,"(%s) The buf argument is not in a valid part of the user address space.\n",s);
        else if (err==WSAENETRESET)     lprintf(bf,500-1,"(%s) The connection must be reset because the Windows Sockets implementation dropped it.\n",s);
        else if (err==WSAENOBUFS)       lprintf(bf,500-1,"(%s) The Windows Sockets implementation reports a buffer deadlock.\n",s);
        else if (err==WSAENOTCONN)      lprintf(bf,500-1,"(%s) The socket is not connected.\n",s);
        else if (err==WSAENOTSOCK)      lprintf(bf,500-1,"(%s) The descriptor is not a socket.\n",s);
        else if (err==WSAEOPNOTSUPP)    lprintf(bf,500-1,"(%s) MSG_OOB was specified, but the socket is not of type SOCK_STREAM.\n",s);
        else if (err==WSAESHUTDOWN)     lprintf(bf,500-1,"(%s) The socket has been shutdown; it is not possible to sendln on a socket after shutdown has been invoked with how set to 1 or 2.\n",s);
        else if (err==WSAEWOULDBLOCK)   lprintf(bf,500-1,"(%s) The socket is marked as non-blocking and the requested operation would block.\n",s);
        else if (err==WSAEMSGSIZE)      lprintf(bf,500-1,"(%s) The socket is of type SOCK_DGRAM, and the datagram is larger than the maximum supported by the Windows Sockets implementation.\n",s);
        else if (err==WSAEINVAL)        lprintf(bf,500-1,"(%s) The socket has not been bound with bind.\n",s);
        else if (err==WSAECONNABORTED)  lprintf(bf,500-1,"(%s) The virtual circuit was aborted due to timeout or other failure.\n",s);
        else if (err==WSAECONNRESET)    lprintf(bf,500-1,"(%s) The virtual circuit was reset by the remote side.\n",s);
        else if (err==WSAETOOMANYREFS)  lprintf(bf,500-1,"(%s) Too many refs.\n",s);
        else if (err==WSAETIMEDOUT)     lprintf(bf,500-1,"(%s) Timedout\n",s);
        else if (err==WSAECONNREFUSED)  lprintf(bf,500-1,"(%s) Connection Refused\n",s);
        else if (err==WSAEDESTADDRREQ)  lprintf(bf,500-1,"(%s) DestAddrReq\n",s);
        else if (err==WSAEMSGSIZE)      lprintf(bf,500-1,"(%s) Message Size\n",s);
        else if (err==WSAEADDRINUSE)    lprintf(bf,500-1,"(%s) Address in use\n",s);
        else if (err==WSAEADDRNOTAVAIL) lprintf(bf,500-1,"(%s) Address not avail\n",s);
        else if (err==WSAENETUNREACH)   lprintf(bf,500-1,"(%s) Network Unreachable\n",s);
        else if (err==WSAENETRESET)     lprintf(bf,500-1,"(%s) Network Reset\n",s);
        else if (err==WSAENOBUFS)       lprintf(bf,500-1,"(%s) No bufs\n",s);
        else if (err==WSAESHUTDOWN)     lprintf(bf,500-1,"(%s) Shutdown\n",s);
        else if (err==WSAENAMETOOLONG)  lprintf(bf,500-1,"(%s) Name too long\n",s);
        else if (err==WSAEHOSTDOWN)     lprintf(bf,500-1,"(%s) Host down\n",s);
        else if (err==WSAEHOSTUNREACH)  lprintf(bf,500-1,"(%s) Host Unreachable\n",s);
        else if (err==WSAENOTEMPTY)     lprintf(bf,500-1,"(%s) Not Empty\n",s);
        else lprintf(bf,500-1,"(%s) Socket Unknown error code %d \n",s,err);
        return bf;
}
#else
void rad_tcp_last(void)
{
        werrno = errno;
}
char *rad_tcp_error(void)
{
        static char bf[1000];
        strcpy(bf,strerror(werrno));
        return bf;
}
#endif

UINT4 ipstr2long(char *ip_str)
{
        char    buf[6];
        char    *ptr;
        int     i;
        int     count;
        UINT4   ipaddr;
        int     cur_byte;

        ipaddr = (UINT4)0;
        for(i = 0;i < 4;i++) {
                ptr = buf;
                count = 0;
                *ptr = '\0';
                while(*ip_str != '.' && *ip_str != '\0' && count < 4) {
                        if(!isdigit(*ip_str)) {
                                return((UINT4)0);
                        }
                        *ptr++ = *ip_str++;
                        count++;
                }
                if(count >= 4 || count == 0) {
                        return((UINT4)0);
                }
                *ptr = '\0';
                cur_byte = atoi(buf);
                if(cur_byte < 0 || cur_byte > 255) {
                        return((UINT4)0);
                }
                ip_str++;
                ipaddr = ipaddr << 8 | (UINT4)cur_byte;
        }
        return(ipaddr);
}

typedef struct {char *name; int id; int type; } DICINPUT;
static DICINPUT dicinput[]= {
        "User-Name", 1,PW_TYPE_STRING
       ,"Password", 2,PW_TYPE_STRING
       ,"CHAP-Password", 3,PW_TYPE_STRING
       ,"NAS-IP-Address", 4, PW_TYPE_IPADDR
       ,"NAS-Port-Id", 5, PW_TYPE_INTEGER
       ,"Service-Type", 6, PW_TYPE_INTEGER
       ,"Framed-Protocol", 7, PW_TYPE_INTEGER
       ,"Framed-IP-Address", 8, PW_TYPE_IPADDR
       ,"Framed-IP-Netmask", 9, PW_TYPE_IPADDR
       ,"Framed-Routing", 10, PW_TYPE_INTEGER
       ,"Filter-Id", 11,PW_TYPE_STRING
       ,"Framed-MTU", 12, PW_TYPE_INTEGER
       ,"Framed-Compression", 13, PW_TYPE_INTEGER
       ,"Login-IP-Host", 14, PW_TYPE_IPADDR
       ,"Login-Service", 15, PW_TYPE_INTEGER
       ,"Login-TCP-Port", 16, PW_TYPE_INTEGER
       ,"Reply-Message", 18,PW_TYPE_STRING
       ,"Callback-Number", 19,PW_TYPE_STRING
       ,"Callback-Id", 20,PW_TYPE_STRING
       ,"Framed-Route", 22,PW_TYPE_STRING
       ,"Framed-IPX-Network", 23, PW_TYPE_IPADDR
       ,"State", 24,PW_TYPE_STRING
       ,"Class", 25,PW_TYPE_STRING
       ,"Vendor-Specific", 26,PW_TYPE_STRING
       ,"Session-Timeout", 27, PW_TYPE_INTEGER
       ,"Idle-Timeout", 28, PW_TYPE_INTEGER
       ,"Termination-Action", 29, PW_TYPE_INTEGER
       ,"Called-Station-Id", 30,PW_TYPE_STRING
       ,"Calling-Station-Id", 31,PW_TYPE_STRING
       ,"NAS-Identifier", 32,PW_TYPE_STRING
       ,"Proxy-State", 33,PW_TYPE_STRING
       ,"Login-LAT-Service", 34,PW_TYPE_STRING
       ,"Login-LAT-Node", 35,PW_TYPE_STRING
       ,"Login-LAT-Group", 36,PW_TYPE_STRING
       ,"Framed-AppleTalk-Link", 37, PW_TYPE_INTEGER
       ,"Framed-AppleTalk-Network", 38, PW_TYPE_INTEGER
       ,"Framed-AppleTalk-Zone", 39,PW_TYPE_STRING

       ,"Acct-Status-Type", 40, PW_TYPE_INTEGER
       ,"Acct-Delay-Time", 41, PW_TYPE_INTEGER
       ,"Acct-Input-Octets", 42, PW_TYPE_INTEGER
       ,"Acct-Output-Octets", 43, PW_TYPE_INTEGER
       ,"Acct-Session-Id", 44,PW_TYPE_STRING
       ,"Acct-Authentic", 45, PW_TYPE_INTEGER
       ,"Acct-Session-Time", 46, PW_TYPE_INTEGER
       ,", Acct-Input-Packets", 47, PW_TYPE_INTEGER
       ,", Acct-Output-Packets", 48, PW_TYPE_INTEGER
       ,"Acct-Terminate-Cause", 49, PW_TYPE_INTEGER
       ,"Acct-Multi-Session-Id", 50,PW_TYPE_STRING
       ,"Acct-Link-Count", 51, PW_TYPE_INTEGER

       ,"CHAP-Challenge", 60,PW_TYPE_STRING
       ,"NAS-Port-Type", 61, PW_TYPE_INTEGER
       ,"Port-Limit", 62, PW_TYPE_INTEGER
       ,"Login-LAT-Port", 63, PW_TYPE_INTEGER

       ,"Connect-Info", 77,PW_TYPE_STRING

       ,"Huntgroup-Name", 221,PW_TYPE_STRING
       ,"User-Category", 1029,PW_TYPE_STRING
       ,"Group-Name", 1030,PW_TYPE_STRING
       ,"Simultaneous-Use", 1034, PW_TYPE_INTEGER
       ,"Strip-User-Name", 1035, PW_TYPE_INTEGER
       ,"Fall-Through", 1036, PW_TYPE_INTEGER
       ,"Add-Port-To-IP-Address", 1037, PW_TYPE_INTEGER
       ,"Exec-Program", 1038,PW_TYPE_STRING
       ,"Exec-Program-Wait", 1039,PW_TYPE_STRING
       ,"Hint", 1040,PW_TYPE_STRING
       ,"Pam-Auth", 1041,PW_TYPE_STRING
       ,"Login-Time", 1042,PW_TYPE_STRING

       ,"Expiration",  21, PW_TYPE_DATE
       ,"Auth-Type", 1000, PW_TYPE_INTEGER
       ,"Menu", 1001,PW_TYPE_STRING
       ,"Termination-Menu", 1002,PW_TYPE_STRING
       ,"Prefix", 1003,PW_TYPE_STRING
       ,"Suffix", 1004,PW_TYPE_STRING
       ,"Group", 1005,PW_TYPE_STRING
       ,"Crypt-Password", 1006,PW_TYPE_STRING
       ,"Connect-Rate", 1007, PW_TYPE_INTEGER
       ,NULL,0,0
};


DICT_ATTR *dict_attrget(int attribute)
{
        static DICT_ATTR        attr;
        int i;
        for (i=0; dicinput[i].name!=NULL; i++) {
                if (attribute==dicinput[i].id) {
                        attr.value = attribute;
                        strncpy(attr.name,dicinput[i].name,30);
                        attr.type = dicinput[i].type;
                        attr.vendor = 0;
                        return &attr;
                }
        }
        return NULL;
}
#endif
