/* Verify that this user/password is valid per a database. Return 1 if verified, 0 otherwise. Format of connection string (look like internet URL): db://user:password@hostname/table?name&passwd Example connect to Oracle RDBMS at user 'roger' with password 'tiger', to 'host.domain.com' database server, fields name in table is 'name' and 'passwd' in 'oshadow' table: oracle://roger:tiger@host.domain.com/oshadow?name&passwd DONE: 12-nov-1998 Created Add DB support to 'login = db ' 14-nov-1998 Change Tacacs+ version from 0.95 to 3.0.9 18-nov-1998 Added code for Oracle [version 8.0.5] 27-nov-1998 Tested with 30'000 usernames Oracle database Added DB support to global configuration 'default authentication = db ' 28-nov-1998 Added code for NULL database %) 14-dec-1999 Add code for MySQL and also more check FUTURE: Make *_db_verify() the functions is reenterable More security for connection to database GDBM support Separate debug logging Perfomance testing on 10000 records in Oracle database (in guide sayd about 3 auth/sec on Ultra 2 - hmm) ------------------------------------------------------- fil@artelecom.ru http://twister.pp.ru **************************************************************************** PART II I am added some extra extension. Like MySQL and PostgreSQL database support And change most of lines for use dynamic memory allocation. db_accounting added by me. devrim(devrim@gazi.edu.tr) */ #include "tac_plus.h" #ifdef DB #include #include #include #include "db.h" #include "report.h" #include "do_acct.h" #include "main.h" #include "do_author.h" /* for "struct identity" */ #include "utils.h" #ifdef DB_MYSQL #include "db_mysql.h" #endif #ifdef DB_NULL #include "db_null.h" #endif #ifdef DB_PGSQL #include "db_pgsql.h" #endif static int check_db_type TAC_ARGS((char *db_type)); /* The databases recognized by this function */ #define DEFINED_DB {"null","mysql","pgsql"} int db_verify TAC_ARGS((const char *user, const char *users_passwd, const char *str_conn)); int db_verify(user, users_passwd, str_conn) const char *user; /* username ... */ const char *users_passwd; /* ... and given password */ const char *str_conn; /* string connection to database */ { char *buffer; char *db_pref, *db_user, *db_password; char *db_hostname, *db_table,*db_name,*dbfield_name, *dbfield_passwd; int ret; if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "verify %s by database at %s", user, str_conn); buffer = db_pref = (char *) tac_malloc( strlen(str_conn) + 1 ); strcpy( buffer, str_conn ); db_user = (char *)strstr( db_pref, "://" ); if( db_user == NULL ){ if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "Error parse db_user"); free(buffer); return(0); } *db_user = '\0'; /* For recognize db authentication database */ if (check_db_type(db_pref)) { report(LOG_DEBUG, "%s DB authentication scheme didn't recognize by tac_plus",db_pref); free(buffer); return(0); } db_user += 3; db_password = (char *)strstr( db_user, ":" ); if( db_password == NULL ){ if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "Error parse db_password"); free(buffer); return(0); } *db_password = '\0'; db_password++; db_hostname = (char *)strstr( db_password, "@" ); if( db_hostname == NULL ){ if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "Error parse db_hostname"); free(buffer); return(0); } *db_hostname = '\0'; db_hostname++; db_name = (char *)strstr( db_hostname, "/" ); if( db_name == NULL ){ if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "Error parse db_name"); free(buffer); return(0); } *db_name = '\0'; db_name++; db_table = (char *)strstr( db_name, "/" ); if( db_table == NULL ){ if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "Error parse db_table"); free(buffer); return(0); } *db_table = '\0'; db_table++; dbfield_name = (char *)strstr( db_table, "?" ); if( dbfield_name == NULL){ if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "Error parse dbfield_name"); free(buffer); return(0); } *dbfield_name = '\0'; dbfield_name++; dbfield_passwd = (char *)strstr( dbfield_name, "&" ); if( dbfield_passwd == NULL){ if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "Error parse dbfield_passwd"); free(buffer); return(0); } *dbfield_passwd = '\0'; dbfield_passwd++; /* Parse database connection string */ if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "db_verify: db_pref=%s, db_user=%s, db_password=%s db_hostname=%s, db_name=%s ,db_table=%s, dbfield_name=%s, dbfield_passwd=%s", db_pref, db_user, db_password, db_hostname, db_name,db_table, dbfield_name, dbfield_passwd); /* Check for empty passwords */ if (users_passwd == NULL || *users_passwd == '\0' || db_password == NULL || *db_password == '\0' ) { if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "One from passwords is empty"); free(buffer); return (0); } ret = 0; /* Run database depend function */ #if defined(DB_ORACLE) if (!strcmp(db_pref, "oracle")) { ret = oracle_db_verify( user, users_passwd, db_user, db_password, db_hostname, db_table, dbfield_name, dbfield_passwd); } #endif #if defined(DB_MYSQL) if (!strcmp(db_pref, "mysql")) { ret = mysql_db_verify( user, users_passwd, db_user, db_password, db_hostname, db_name, db_table, dbfield_name, dbfield_passwd); } #endif #if defined(DB_PGSQL) if (!strcmp(db_pref, "pgsql")) { ret = pgsql_db_verify( user, users_passwd, db_user, db_password, db_hostname,db_name, db_table, dbfield_name, dbfield_passwd); } #endif #if defined(DB_NULL) if (!strcmp(db_pref, "null")) { ret = null_db_verify( user, users_passwd, db_user, db_password, db_hostname ,db_table, dbfield_name, dbfield_passwd); } #endif #if defined(DB_GDBM) if (!strcmp(db_pref, "gdbm")) { gdb_db_verify(); } #endif free(buffer); /* Free unused memory */ return (ret); /* error */ } int db_acct TAC_ARGS((struct acct_rec *rec)); /* Db accounting routine */ int db_acct(rec) struct acct_rec *rec; { char *buffer; char *db_pref, *db_user, *db_password; char *db_hostname, *db_name,*db_table; char *a_username,*s_name,*c_name,*elapsed_time,*bytes_in,*bytes_out; int ret; buffer = db_pref = (char *) tac_malloc( strlen(session.db_acct) + 1 ); strcpy( buffer, session.db_acct); db_user = (char *)strstr( db_pref, "://" ); if( db_user == NULL ){ if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "Error parse db_user"); free(buffer); return(0); } *db_user = '\0'; /* For recognize db accouting database */ if( check_db_type(db_pref) ) { report(LOG_DEBUG, "%s DB accounting scheme didn't recognize by tac_plus",db_pref); free(buffer); return(0); } db_user += 3; db_password = (char *)strstr( db_user, ":" ); if( db_password == NULL ){ if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "Error parse db_password"); free(buffer); return(0); } *db_password = '\0'; db_password++; db_hostname = (char *)strstr( db_password, "@" ); if( db_hostname == NULL ){ if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "Error parse db_hostname"); free(buffer); return(0); } *db_hostname = '\0'; db_hostname++; db_name = (char *)strstr( db_hostname, "/" ); if( db_name == NULL ){ if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "Error parse db_name"); free(buffer); return(0); } *db_name = '\0'; db_name++; db_table = (char *)strstr( db_name, "/" ); if( db_table == NULL ){ if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "Error parse db_table"); free(buffer); return(0); } *db_table = '\0'; db_table++; /* Find some attributes for accounting */ a_username=rec->identity->username; if (a_username==NULL ) { if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG,"db_acct: Can't find username!"); free(buffer); return(0); } s_name=rec->identity->NAS_name; if (s_name==NULL) { if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG,"db_acct: Can't find NAS name!"); free(buffer); return(0); } c_name=find_attr_value("addr", rec->args, rec->num_args); if (c_name==NULL) { if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG,"db_acct: Can't find client adress!"); /* Can't find client adress so give NAC_address attribute value */ c_name=rec->identity->NAC_address; } elapsed_time=find_attr_value("elapsed_time", rec->args, rec->num_args); if (elapsed_time==NULL) { if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG,"db_acct: Can't get elapsed time!"); free(buffer); return(0); } bytes_in=find_attr_value("bytes_in", rec->args, rec->num_args); if (bytes_in==NULL) bytes_in="0"; bytes_out=find_attr_value("bytes_out", rec->args, rec->num_args); if (bytes_out==NULL) bytes_out="0"; /* Parse database connection string */ if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "db_verify: db_pref=%s, db_user=%s,db_password=%s , db_hostname=%s, db_name=%s ,db_table=%s ", db_pref, db_user, db_password, db_hostname, db_name,db_table ); /* Check for empty passwords */ if (db_user == NULL || db_password == '\0' ) { if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "One from passwords is empty"); free(buffer); return (0); } ret = 0; /* Run database depend function */ #if defined(DB_ORACLE) if (!strcmp(db_pref, "oracle")) { ret = oracle_db_acct( db_user, db_password, db_hostname, db_name, db_table); } #endif #if defined(DB_MYSQL) if (!strcmp(db_pref, "mysql")) { ret = mysql_db_acct( db_user, db_password, db_hostname, db_name, db_table,s_name,c_name,a_username,elapsed_time,bytes_in,bytes_out); } #endif #if defined(DB_PGSQL) if (!strcmp(db_pref, "pgsql")) { ret = pgsql_db_acct( db_user, db_password, db_hostname, db_name, db_table,s_name,c_name,a_username,elapsed_time,bytes_in,bytes_out); } #endif #if defined(DB_NULL) if (!strcmp(db_pref, "null")) { ret = null_db_acct( db_user, db_password, db_hostname, db_name, db_table,s_name,c_name,a_username,elapsed_time,bytes_in,bytes_out); } #endif #if defined(DB_GDBM) if (!strcmp(db_pref, "gdbm")) { gdb_db_acct(); } #endif free(buffer); /* Free unused memory */ return (ret); /* error */ } static int check_db_type TAC_ARGS((char *db_type)); /* For checking DB type */ static int check_db_type(db_type) char *db_type; { char *dbp[]=DEFINED_DB; int ret=1,i; for (i=0; dbp[i] ; i++ ) { if(!strcmp(db_type,dbp[i])) { ret=0; break; } } return ret; } #else /* DB */ TAC_SOURCEFILE_EMPTY #endif /* DB */