#pragma module RAD_EXT_ACCT2ORA "RAD_EXT_ACCT2ORA-1-X" /* **++ ** FACILITY: RADIUS-VMS ** ** MODULE DESCRIPTION: ** ** External module for processing an accounting for RADIUS-VMS server. ** ** AUTHORS: ** ** Copyright © Ruslan R. Laishev 2000 ** ** CREATION DATE: 11-MAR-2000 ** ** DESIGN ISSUES: ** ** This module supposed to contains external user-written pocedures ** are called from RADIUS-VMS server. ** ** N.B. Since RADIUS-VMS server is a DEC Threads application, you should ** write thread safe code for the ACCOUNTING routine, using ** reenterancy or the syncronization technics. ** ** N.B. The INIT & CLEANUP routines is called when all auth-threads is not ran. ** ** N.B. RADIUS-VMS makes hardcoded references to event flags 19-22. ** ** To build this module (ALPHA): ** ** $CC/PREFFIX=ALL RAD_EXT_ACCT2ORA.C/REENTRANCY=MULTITHREAD - ** /INCLUDE=([],ORA_RDBMS,ORA_OCI_DEMO)/NOWARN ** ** $CREATE RAD_EXT_ACCT2ORA.OPT ** SYMBOL_VECTOR=(INIT=PROCEDURE,ACCOUNTING=PROCEDURE,CLEANUP=PROCEDURE) ** ** ** $@ORA_RDBMS:lnocic RAD_EXT_ACCT2ORA RAD_EXT_ACCT2ORA,RAD_EXT_ACCT2ORA.OPT/OPT i ** ** To build this module (VAX): ** $CC/PREFFIX=ALL RAD_EXT_ACCT2ORA.C - ** /INCLUDE=([],ORA_RDBMS,ORA_OCI_DEMO) ** $CREATE RAD_EXT_ACCT2ORA.OPT ** UNIVERSAL=INIT,ACCOUNTING,CLEANUP ** ** ** $@ORA_RDBMS:lnocic RAD_EXT_ACCT2ORA RAD_EXT_ACCT2ORA,RAD_EXT_ACCT2ORA.OPT/OPT i ** ** DEFINE/SYSTEM/EXEC ORALOGIN "scott/tiger" ** DEFINE/SYSTEM/EXEC RADIUS_EXT_ACCT dev:[dir]RAD_EXT_ACCT2ORA.EXE ** ** ORACLE stuff see in the RAD_EXT_ACCT2ORA.ORA_SQL ** ** MODIFICATION HISTORY: ** ** 19-MAR-2001 RRL Added a Calling/Called station ID(s), ** an account was removed. Added a passing of the realm. ** {@tbs@}... **-- */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __STDC__ #include #else #include #endif /* ** ** MACRO DEFINITIONS ** */ #define INIT_SDESC(dsc, len, ptr) {(dsc).dsc$b_dtype = DSC$K_DTYPE_T;\ (dsc).dsc$b_class = DSC$K_CLASS_S; (dsc).dsc$w_length = (short) (len);\ (dsc).dsc$a_pointer = (ptr);} #define NATIVE 1 #define VERSION_7 2 /* ** CONFIGURATION PARAMETERS, ORACLE GLOBAL VARIABLES */ static Lda_Def lda; static Cda_Def cda; static unsigned char hda[256]; static pthread_mutex_t ora_lockwr; unsigned char sql_init[] = "\ begin\ :retcode := radacct.init;\ end;"; unsigned char sql_accounting[] = "\ begin\ :retcode := radacct.accounting\ (:end_time,:sess_id, \ :port_num,:username,:account,:port_type, \ :protocol,:client,:frammed_ip,:start_time, \ :status,:speed,:inp_octs,:out_octs);\ end;"; unsigned char sql_cleanup[] = "\ begin\ :retcode := radacct.cleanup;\ end;"; /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Put message to standard output device (SYS$OUTPUT), decode and append ** ORACLE OCI text of error message. ** ** FORMAL PARAMETERS: ** ** status: ** ORACLE OCI status code ** ** RETURN VALUE: ** ** None. ** ** **-- */ void ora_ocimsg ( int status ) { int len; char buf[1024]; len = oerhms(&lda, status, buf, sizeof (buf)); printf("%.*s\n",len,buf); } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Initializes the context used by this module. Opening ORACLE ** session, login. ** ** If you do not need to maintain any context between calls to your ** ACCOUNTING routines, it is OK to simply ** set the context pointer to NULL. If you do this, your CLEANUP ** routine will never be called. ** ** FORMAL PARAMETERS: ** ** context: address of a pointer to the allocated context ** ** RETURN VALUE: ** ** VMS condition value ** **-- */ int INIT (void **context) { int status = 0,retcode = 0; char oralogin[128]; oralogin[0] = '/'; oralogin[1] ='\0'; if ( getenv("ORALOGIN") ) strncpy(oralogin,getenv("ORALOGIN"),sizeof(oralogin)-1); /* ** Open session to ORACLE Server */ status = olog(&lda, hda, oralogin,-1, NULL,0,0,0, OCI_LM_DEF); /* ** Open context data area (cursor) , init treda-safe mode */ status = status?status:oopen(&cda, &lda,NULL, -1, -1,NULL, -1); status = status?status:opinit(OCI_EV_TSF); /* ** RADACCT.INIT() */ status = status?status:oparse(&cda,sql_init,-1,0,VERSION_7); status = status?status:obndrv(&cda,":retcode",-1,&retcode, sizeof(int),SQLT_INT,-1,0,0,-1,-1); status = status?status:oexec(&cda); if ( status ) { ora_ocimsg(status); return SS$_ABORT; } #if __VMS_VER >= 70000000 if ( status = pthread_mutex_init(&ora_lockwr,NULL) ) #else if ( status = pthread_mutex_init(&ora_lockwr,pthread_mutexattr_default) ) #endif { printf("%s\n",strerror(status)); return SS$_ABORT; } /* ** Preparse RADACCT.ACCOUNTING() */ if ( status = oparse(&cda,sql_accounting,-1,0,VERSION_7) ) { ora_ocimsg(status); return SS$_ABORT; } return SS$_NORMAL; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Processing the accounting information. ** ** FORMAL PARAMETERS: ** ** context: address of a pointer to the allocated context ** user: address of an username character string,ASCIZ ** sess_id: session ID ** proto: protocol name (PPP,Telnet etc.), ASCIZ ** nas_ip_name: NAS IP name or IP address character string ** nas_ip_namelen: length of the nas-ip_name string ** nas_port_t: NAS port type character string,ASCIZ ** nas_port: NAS port ID ** frmd_info: Frammed-IP character string,ASCIZ ** in_bytes: a number of bytes transffered to the user ** out_bytes: a number of bytes transffered from the user ** start_time: a login time in VMS binary format ** end_time: a loggout time in VMS binary format ** speed: connection speed ** called_id: Called-Station-Id string ** called_id_len: length of the Called-Station-Id string ** calling_id: Calling-Station-Id string ** calling_id_len: length of the Calling-Station-Id string ** realm: a realm string ** realmlen: a length of the realm string ** ** RETURN VALUE: ** ** 0 = OK ** 1 = OK skip accounting actions in the RADIUS-VMS **-- */ int ACCOUNTING (void **context, unsigned char *user, int sess_id, unsigned char *proto, unsigned char *nas_ip_name, short nas_ip_namelen, unsigned char *nas_port_t, int nas_port, unsigned char *frmd_info, int in_bytes, int out_bytes, int *start_time, int *end_time, int term_status, int speed, char *called_id, short called_id_len, char *calling_id, short calling_id_len, char *realm, short realmlen ) { int status = 0,retcode = 0; unsigned char start_date[32],end_date[32]; struct dsc$descriptor tmp_dsc; INIT_SDESC(tmp_dsc,sizeof(start_date),start_date); if ( !(1 & (status = sys$asctim(0,&tmp_dsc,start_time,0))) ) lib$signal(status); INIT_SDESC(tmp_dsc,sizeof(end_date),end_date); if ( !(1 & (status = sys$asctim(0,&tmp_dsc,end_time,0))) ) lib$signal(status); /* ** Wait for condition, lock mutex */ if ( status = pthread_mutex_lock(&ora_lockwr) ) { printf("lockwr:%s\n",strerror(status)); return 0; } status = status?status:obndrv(&cda,":end_time",-1,end_date, 20,SQLT_CHR,-1,0,0,-1,-1); status = status?status:obndrv(&cda,":sess_id",-1, &sess_id, sizeof(int),SQLT_INT,-1,0,0,-1,-1); status = status?status:obndrv(&cda,":port_num",-1, &nas_port, sizeof(int),SQLT_INT,-1,0,0,-1,-1); status = status?status:obndrv(&cda,":username",-1,user,-1,SQLT_CHR,-1,0,0,-1,-1); status = status?status:obndrv(&cda,":account",-1,acc,-1,SQLT_CHR,-1,0,0,-1,-1); status = status?status:obndrv(&cda,":port_type",-1,nas_port_t, -1,SQLT_CHR,-1,0,0,-1,-1); status = status?status:obndrv(&cda,":protocol",-1,proto, -1,SQLT_CHR,-1,0,0,-1,-1); status = status?status:obndrv(&cda,":client",-1,nas_ip_name, nas_ip_namelen,SQLT_CHR,-1,0,0,-1,-1); status = status?status:obndrv(&cda,":frammed_ip",-1,frmd_info, -1,SQLT_CHR,-1,0,0,-1,-1); status = status?status:obndrv(&cda,":start_time",-1,start_date, 20,SQLT_CHR,-1,0,0,-1,-1); status = status?status:obndrv(&cda,":status",-1,&term_status, sizeof(int),SQLT_INT,-1,0,0,-1,-1); status = status?status:obndrv(&cda,":speed",-1, &speed, sizeof(int),SQLT_INT,-1,0,0,-1,-1); status = status?status:obndrv(&cda,":inp_octs",-1,&in_bytes, sizeof(int),SQLT_INT,-1,0,0,-1,-1); status = status?status:obndrv(&cda,":out_octs",-1,&out_bytes, sizeof(int),SQLT_INT,-1,0,0,-1,-1); status = status?status:obndrv(&cda,":retcode",-1,&retcode, sizeof(int),SQLT_INT,-1,0,0,-1,-1); status = status?status:oexec(&cda); pthread_mutex_unlock(&ora_lockwr); if ( status ) ora_ocimsg(status); return 0; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Cleans up the context allocated in the INIT routine. Not called ** if the INIT routine set the context to NULL. ** ** FORMAL PARAMETERS: ** ** context: address of a pointer to the allocated context ** ** RETURN VALUE: ** ** VMS condition code **-- */ int CLEANUP (void **context) { int status = 0,retcode = 0; /* ** Preparse RADACCT.CLEANUP() */ status = status?status:oparse(&cda,sql_cleanup,-1,0,VERSION_7); status = status?status:obndrv(&cda,":retcode",-1, &retcode,sizeof(int),SQLT_INT,-1,0,0,-1,-1); status = status?status:oexec(&cda); if ( status ) ora_ocimsg(status); /* ** Destroy context , and logoff */ if ( status = oclose(&cda) ) ora_ocimsg(status); if ( status = ologof(&lda) ) ora_ocimsg(status); if ( status = pthread_mutex_destroy(&ora_lockwr) ) printf("%s\n",strerror(status)); return SS$_NORMAL; } #if 0 void main (void) { int status,start_time[2],end_time[2]; void *context; $DESCRIPTOR(start_time_dsc,"23-FEB-2000 23:00:00"); $DESCRIPTOR(end_time_dsc,"15-MAR-2000 12:00:00"); if ( !(1 & (status = sys$bintim(&start_time_dsc,start_time))) ) lib$signal(status); if ( !(1 & (status = sys$bintim(&end_time_dsc,end_time))) ) lib$signal(status); if ( !(1 & (status = INIT (&context))) ) sys$exit(status); status = ACCOUNTING(&context, "SysOp", 111198765L, "SuperPPP", "SuperNAS",8, "SuperT3", 13L, "172.16.1.30", 133L, 135L, start_time, end_time, 3L, 38400L, "MIS"); if ( context && !(1 & (status = CLEANUP (&context))) ) sys$exit(status); } #endif