/* * ipass.c - Ipass alliance routines * * These routines are called by the main program to talk to an Ipass server. * * The samples we have provided here may be used at a site running RADIUS */ /* * * Copyright 1996 iPass Alliance Inc. All rights reserved. * * Portions may be copyright by: * * Lucent Technologies Remote Access * 4464 Willow Road * Pleasanton, CA 94588 * * Copyright 1992-1999 Lucent Technologies, Inc. * */ #ifdef IPASS #ident "@(#)$Name: $:$Id: ipass.c,v 1.2 1999/06/23 23:40:39 cdr Exp $" #include #include #ifdef HAVE_SYS_CDEFS_H # include #endif #include #if HAVE_SYS_WAIT_H # include #endif #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) #endif #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif #include #include #include #include #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_MEMORY_H # include #endif #if STDC_HEADERS # include # include #else # ifndef HAVE_STRCHR # define strchr index # define strrchr rindex # endif # ifdef HAVE_STRINGS_H # include # endif /* XXX should really declare string functions here... */ # ifndef HAVE_MEMCPY # define memcpy(d, s, n) bcopy((s), (d), (n)) # define memmove(d, s, n) bcopy((s), (d), (n)) # endif #endif #include #include #include #include #include #include #include "radius.h" /* includes local md5.h */ #define IPASS_REMOTE_ID_CHAR '@' struct sockaddr_in rad_addr,cli_addr; extern int server_fd; extern int errno; /* forward declarations */ int ipassinit(); int decode_passwd (char *, UINT4, char *, char *); void handle_response (int, AUTH_REQ *, ipinfo_t *, ipauth_t *, int, int); void dump_to_disk (char *, int, char *); int raddebug = 0; int ipassinit() { /* init iPass library */ return ipass_init(0, (char **) NULL, IPASS_PROGNM_AUTHD); } int rad_forw_ipass(authreq, radius_fd, buff) AUTH_REQ *authreq; int radius_fd; char *buff; { AUTH_HDR *auth; ipinfo_t ipinfo; ipauth_t ipauth; ipacct_t ipacct; char *ptr,*sptr, *p; char ibuff[BUFSIZ]; char vector[16]; char passwd[128]; char user_name[IPASS_MAXNAMLEN+IPASS_MAXDOMLEN+1+1]; char nas_ip[(4*3)+3+1]; int attrvalue, i,j; u_short length, attribute, attrlen; int ret_code = 0; time_t ttime; auth = (AUTH_HDR*)buff; ipinfo.service = IPASS_SERV_UNKNOWN; ipinfo.direction = IPASS_DIR_UNKNOWN; ipinfo.nas_ses_id[0] = '\0'; ipauth.host_ip.s_addr = INADDR_ANY; ipacct.user_ip.s_addr = INADDR_ANY; ipacct.user_mask.s_addr = INADDR_ANY; passwd[0] = '\0'; ipauth.passwd[0] = '\0'; switch(auth->code){ case PW_AUTHENTICATION_REQUEST: trace("received authentication request, id: %d", auth->id); break; case PW_ACCOUNTING_REQUEST: trace("received accounting request, id: %d", auth->id); break; default: trace("received unknown request: %d", auth->code); return; } ptr=&buff[4]; for (i=0;ilength); ptr=&buff[0]; ptr+=AUTH_HDR_LEN; length-=AUTH_HDR_LEN; /* now pointing at code of first data field */ if (raddebug){ dump_to_disk((char *)buff,(int)auth->length,"Request"); } while (length > 2) { attribute = *ptr++; attrlen = *ptr++; sptr=ptr; if (attrlen < 2) { /* malformed packet, can't do anything but quit */ length = 0; continue; } if (attrlen == 2){ /* this is illegal, but one site who shall remain nameless sends these packets all the time */ length -= 2; continue; } attrlen -= 2; ptr+=attrlen-1; attrvalue=*ptr++; switch (attribute){ case PW_CLIENT_ID: memcpy(&ipinfo.nas_ip, sptr, sizeof(UINT4)); sptr += 4; break; case PW_LOGIN_HOST: memcpy(&ipauth.host_ip, sptr, sizeof(UINT4)); sptr += 4; break; case PW_PASSWORD: for(i=0;icode == PW_AUTHENTICATION_REQUEST){ if (passwd[0]) { if (!decode_passwd(passwd, authreq->ipaddr, auth->vector, authreq->secret)) return -1; strncpy(ipauth.passwd, passwd, sizeof(ipauth.passwd) - 1); ipauth.passwd[sizeof(ipauth.passwd) - 1] = '\0'; } ipass_remote_auth(&ipinfo, &ipauth); if (ipauth.errcode != IPASS_STATUS_OK) { trace("ipass_remote_auth: failed %d: %s", ipauth.errcode, ipauth.status ? ipauth.status : ""); return -1; } ret_code = ipauth.auth_reply == IPASS_AUTH_OK ? 1 : 0; } else{ ipacct.ip = 0; ipacct.op = 0; ipacct.ic = 0; ipacct.oc = 0; ipass_remote_acct(&ipinfo, &ipacct); if (ipacct.errcode != IPASS_STATUS_OK) { trace("ipass_remote_acct: failed %d: %s", ipacct.errcode, ipacct.status ? ipacct.status : ""); return -1; } ret_code = 1; } handle_response(radius_fd,authreq, &ipinfo,&ipauth,auth->code,ret_code); return 1; } /* handle_response - decode reply from ipass and send the return packet back to NAS */ void handle_response (radius_fd,authreq,ipinfop,ipauthp, auth_code,ret_code) int radius_fd; AUTH_REQ *authreq; ipinfo_t *ipinfop; ipauth_t *ipauthp; int auth_code; int ret_code; { AUTH_HDR *authreply; int i; char *ptr; UINT4 lvalue; u_short length; unsigned char replybuff[4096]; unsigned char vector[AUTH_VECTOR_LEN]; struct sockaddr_in nas_addr; authreply = (AUTH_HDR *)replybuff; memset(replybuff,0,sizeof(replybuff)); /* start building reply packet */ authreply->id = authreq->id; memcpy(authreply->vector,authreq->vector,AUTH_VECTOR_LEN); length=AUTH_HDR_LEN; authreply->code = PW_AUTHENTICATION_REJECT; if (ret_code) { ptr = (char *) authreply->data; if (auth_code == PW_AUTHENTICATION_REQUEST) { authreply->code = PW_AUTHENTICATION_ACK; if ((ipauthp->serv_req == IPASS_SERV_RLOGIN)|| (ipauthp->serv_req == IPASS_SERV_TELNET)|| (ipauthp->serv_req == IPASS_SERV_PPP)|| (ipauthp->serv_req == IPASS_SERV_SLIP)){ *ptr++ = PW_USER_SERVICE_TYPE; *ptr = 6; length += *ptr; ptr += 4; switch (ipauthp->serv_req) { case IPASS_SERV_RLOGIN: case IPASS_SERV_TELNET: *ptr++ = PW_LOGIN_USER; *ptr++ = PW_LOGIN_SERVICE; *ptr = 6; length += *ptr; ptr += 4; if (ipauthp->serv_req == IPASS_SERV_TELNET) *ptr++ = PW_TELNET; else *ptr++ = PW_RLOGIN; break; case IPASS_SERV_PPP: case IPASS_SERV_SLIP: *ptr++ = PW_FRAMED_USER; *ptr++ = PW_FRAMED_PROTOCOL; *ptr = 6; length += *ptr; ptr += 4; if (ipauthp->serv_req == IPASS_SERV_PPP) *ptr++ = PW_PPP; else *ptr++ = PW_SLIP; break; } if (ipauthp->host_ip.s_addr != INADDR_ANY) { *ptr++ = PW_LOGIN_HOST; *ptr++ = sizeof(UINT4) + 2; memcpy(ptr, &ipauthp->host_ip.s_addr, sizeof(UINT4)); ptr += sizeof(UINT4); length += sizeof(UINT4) + 2; } if (ipauthp->host_port) { *ptr++ = PW_LOGIN_TCP_PORT; *ptr++ = sizeof(UINT4) + 2; lvalue = htons(ipauthp->host_port); memcpy(ptr, &lvalue, sizeof(UINT4)); ptr += sizeof(UINT4); length += sizeof(UINT4) + 2; } } else{ trace("unsupported iPass service request %d, ignored.", ipauthp->serv_req); } } else authreply->code = PW_ACCOUNTING_RESPONSE; } authreply->length = htons(length); memcpy(replybuff+length,authreq->secret,strlen(authreq->secret)); md5_calc(vector,replybuff,length+strlen(authreq->secret)); memcpy(authreply->vector,vector,AUTH_VECTOR_LEN); /* don't need secret anymore, trash it from reply packet */ memset(replybuff+length,0,strlen(authreq->secret)); memset((char*) &nas_addr,0, sizeof(nas_addr)); nas_addr.sin_family = AF_INET; nas_addr.sin_addr.s_addr = htonl(authreq->ipaddr); nas_addr.sin_port = htons(authreq->udp_port); if (sendto(radius_fd,(char*)replybuff,length,0, (struct sockaddr*)&nas_addr,sizeof(nas_addr)) == -1) { trace("remote sendto NAS %s failed, error %d", ipaddr2strp(ntohl(nas_addr.sin_addr.s_addr)), errno); } else { trace("remote sendto NAS %s okay", ipaddr2strp(ntohl(nas_addr.sin_addr.s_addr))); } if (raddebug) { dump_to_disk((char *)replybuff,(int)length,"Reply"); } return; } int decode_passwd (passwd,ipaddr,vector,shared_secret) char *passwd; UINT4 ipaddr; char *vector; char *shared_secret; { unsigned char md5obuf[256]; unsigned char md5ibuf[256]; int i,j; for (i=0;i 0) { fprintf(fp,"%3x ",j); j+=16; for (i=0; i<16; i++,bp++,count--) { if (count > 0) { fprintf(fp,"%s ",X2(*bp)); ASC[i] = '.'; if (*bp >= ' ' && *bp <= '~') ASC[i] = *bp; } else { fprintf(fp," "); ASC[i] = ' '; } if (i == 7) fprintf(fp," "); } ASC[16] = 0; fprintf(fp," *%s*\n",ASC); } /**/ fclose(fp); /**/ } char *X2 (val) register int val; { static char buff[3]; register int x; x = (val>>4) & 0xf; if (x >= 10) x += 'A' - 10; else x+= '0'; buff[0] = (char) x; x = val & 0xf; if (x >= 10) x += 'A' - 10; else x+= '0'; buff[1] = (char) x; buff[2] = 0; return(buff); } #ifdef NO_STRERROR /* * system has no strerror in standard libraries, so define our own */ char * strerror(err) int err; { extern int sys_nerr; static char *unknown = "unknown errno"; if (err < sys_nerr) { return sys_errlist[err]; } return unknown; } #endif /* NO_STRERROR */ #else /* IPASS */ #include #include "radius.h" /* XXX includes local md5.h */ /* dummy entry points */ int ipassinit() { return 0; } int rad_forw_ipass(authreq, activefd, buffer) AUTH_REQ *authreq; int activefd; char *buffer; { extern char *progname; char *req2strp(); log_err("%s: no ipass support, %s cannot be forwarded\n", progname, req2strp(authreq)); return 0; } #endif /* IPASS */