📄 extens.c
字号:
/* * Copyright (C) 1999-2004 Francesco P. Lovergine. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms stated in the LICENSE file which should be * enclosed with sources. */static char rcsid[] = "$Id: extens.c,v 1.9.2.3 2004/08/27 21:45:16 flovergine Exp $";#include "yard.h"#include "global.h"/* This structure is used for 3COM boxes */static int usr_speeds[53]={0, 300, 1200, 2400, 4800, 7200, 9600, 12000, 14400, 16800, 19200, 21600,28800, 38400, 57600, 115200, 288000, 751200, 120075, 24000, 26400, 31200,33600, 33333, 37333, 41333, 42666, 44000, 45333, 46666, 48000, 49333, 50666,52000, 53333, 54666, 56000, 57333, 64000, 25333, 26666, 28000, 29333, 30666,32000, 34666, 36000, 38666, 40000, 58666, 60000, 61333, 62666};/* * check_logins - see if maximum number of logins was not reached */int check_logins(char *user, const int max_logins){ char dbfile_name[PATH_MAX]; GDBM_FILE dbf; datum key, content; user_entry *ue; struct tm *time_info; time_t crt_time = time(NULL); time_info = localtime(&crt_time); snprintf(dbfile_name,sizeof(dbfile_name), "%s/%d/%s", radacct_dir,1900+time_info->tm_year,RADIUS_USER_STATS); dbf = gdbm_open(dbfile_name,0,GDBM_READER,0600,NULL); if (dbf == NULL) { return 0; } /* Build the key */ key.dptr = user; key.dsize = strlen(user); content = gdbm_fetch(dbf,key); if (content.dptr == NULL) { /* not here, at least one login is allowed */ gdbm_close(dbf); return 0; } ue = (user_entry *)content.dptr; if (ue->logins >= max_logins) { gdbm_close(dbf); if ( content.dptr!=NULL ) free( content.dptr ); return -2; } gdbm_close(dbf); if ( content.dptr!=NULL ) free( content.dptr ); return 0;}/* * check_maxtime - see if maximum DAILY/MONTHLY/YEARLY online time is reached */int check_maxtime(char *user, const int hours, const int kind){ char dbfile_name[PATH_MAX]; GDBM_FILE dbf; datum key, content; user_entry *ue; struct tm *time_info; UINT4 counter; int i,j; time_t crt_time = time(NULL); time_info = localtime(&crt_time); snprintf(dbfile_name, sizeof(dbfile_name), "%s/%d/%s", radacct_dir,1900+time_info->tm_year,RADIUS_USER_STATS); dbf = gdbm_open(dbfile_name,0,GDBM_READER,0600,NULL); if (dbf == NULL) { return 0; } /* Build the key */ key.dptr = user; key.dsize = strlen(user); content = gdbm_fetch(dbf,key); if (content.dptr == NULL) { /* not here, login is allowed */ gdbm_close(dbf); return 0; } ue = (user_entry *)content.dptr; switch ( kind ) { case DAY_LIMIT: if (ue->day[time_info->tm_mon][time_info->tm_mday-1].on_line >= hours*3600) { gdbm_close(dbf); if ( content.dptr!=NULL ) free( content.dptr ); return -2; } break; case MONTH_LIMIT: for ( i=0, counter=0; i<time_info->tm_mday; i++ ) counter += ue->day[time_info->tm_mon][i].on_line; if ( counter >= hours*3600 ) { gdbm_close(dbf); if ( content.dptr!=NULL ) free( content.dptr ); return -2; } break; case YEAR_LIMIT: for ( i=0, counter=0; i<=time_info->tm_mon; i++ ) for ( j=0; i<time_info->tm_mday; i++ ) counter += ue->day[i][j].on_line; if ( counter >= hours*3600 ) { gdbm_close(dbf); if ( content.dptr!=NULL ) free( content.dptr ); return -2; } break; default: log_err("internal error: invalid kind of limit in a" "check_maxtime() call\n"); break; } gdbm_close(dbf); if ( content.dptr!=NULL ) free( content.dptr ); return 0;}/* * clean_user_stats() * * initializes the user_stats database (clear the number of concurent logins) * to avoid starting a new radiusd server with invalid data * */ int clean_user_stats(void){ char dbfile_name[PATH_MAX]; GDBM_FILE dbf; datum key, content, nextkey; struct tm *time_info; time_t crt_time = time(NULL); time_info = localtime(&crt_time); memset(dbfile_name, 0, PATH_MAX); snprintf(dbfile_name, sizeof(dbfile_name), "%s/%d/%s", radacct_dir,1900+time_info->tm_year,RADIUS_USER_STATS); dbf = gdbm_open(dbfile_name,0,GDBM_WRITER|GDBM_SYNC,0600,NULL ); if (dbf == NULL) { /* we couldn't open the databse. That's "okay" in this case... */ return 0; } key = gdbm_firstkey(dbf); while (key.dptr != NULL) { user_entry *p_ue; int retval; content = gdbm_fetch(dbf, key); if (content.dptr == NULL) { nextkey = gdbm_nextkey(dbf,key); free(key.dptr); key = nextkey; continue; } p_ue = (user_entry *)content.dptr; p_ue->logins = 0; content.dsize = sizeof(user_entry); /* rip off any port_entry */ /* update this modified entry */ retval = gdbm_store(dbf, key, content, GDBM_REPLACE); if (retval != 0) { /* odd error updating the database */ key.dptr[key.dsize] = '\0'; log_err("could not reset user_stats entry for '%s'\n", (char *)key.dptr); gdbm_close(dbf); if (content.dptr != NULL) free(content.dptr); if (key.dptr != NULL) free(key.dptr); return -1; } /* update went okay */ if (content.dptr != NULL) free(content.dptr); nextkey = gdbm_nextkey(dbf,key); free(key.dptr); key = nextkey; } gdbm_close(dbf); /* close the database */ /* finished */ return 0;}/* * deny_user returns: * -2 if user is present in RADIUS_DIR/RADIUS_DENY * -3 if user is present in RADIUS_DIR/RADIUS_STOP * 1 if no such user (misa) * 0 if okay * * allow_user returns: * -4 if user is NOT present in RADIUS_DIR/RADIUS_ALLOW * 0 if okay *//* Function: listed_on_file() Purpose: it matches a user against many matching criteria: GROUP: the user belongs to a certain group SHELL: the user has a certain shell GECOS: the user has a Gecos field which _contains_ a certain string USER: the user has a specific name. Notes: string match is case-sensitive. Maybe a regex-match could be interesting. A value of ANY match any user. Francesco Lovergine <f.lovergine@iesi.ba.cnr.it>*/static int listed_on_file(const char *filename, const char *username){ FILE *fp; char buffer[1024]; char value[1024]; static char special[]="ANY"; if ((fp=fopen(filename, "r")) != NULL) { while (fgets(buffer, sizeof(buffer), fp) != NULL) { if ( strlen(buffer)==0 || buffer[0] == '\n' || buffer[0] == '#' || buffer[0] == ';' ) continue; else if ( sscanf(buffer,"USER: %s",value ) == 1 ) { if (strcmp(value,special)==0 || strcmp(username,value) == 0) { fclose(fp); return -1; } } else if ( sscanf(buffer,"GROUP: %s",value ) == 1 ) { if (strcmp(value,special)==0 || unix_group(username,value)) { fclose(fp); return -1; } } else if ( sscanf(buffer,"GECOS: %s",value ) == 1 ) { if (strcmp(value,special)==0 || (strlen(value) && strstr(unix_gecos(username),value)!=NULL) ) { fclose(fp); return -1; } } else if ( sscanf(buffer,"SHELL: %s",value ) == 1 ) { if (strcmp(value,special)==0 || (strlen(value) && strcmp(unix_shell(username),value)==0)) { fclose(fp); return -1; } } else log_err("warning: syntax error in file '%s', line '%s' ignored", filename,buffer); } fclose(fp); } return 0;}/* * The actual function is quite simple ... */int deny_user(const char *username){ char file_name[PATH_MAX]; char buffer[1024]; if (!username || (strlen(username) >= sizeof(buffer))) { /* well, an error, but for this function purpose * should respond with okay... I hate this... */ return 0; } /* first try to open RADIUS_DIR/RADIUS_DENY */ snprintf(file_name, sizeof(file_name), "%s/%s", radius_dir, RADIUS_DENY); if (listed_on_file(file_name, username) < 0) return -2; snprintf(file_name, sizeof(file_name), "%s/%s", radius_dir, RADIUS_STOP); if (listed_on_file(file_name, username) < 0) return -3; return 0;}int allow_user(const char *username){ char file_name[PATH_MAX]; char buffer[1024]; if (!username || (strlen(username) >= sizeof(buffer))) { return -4; } snprintf(file_name,sizeof(file_name),"%s/%s", radius_dir, RADIUS_ALLOW); if (listed_on_file(file_name, username) < 0) return 0; return -4;}/* * Builds a radlast structure from an AUTHREQ_HDR packet */static int build_radlast_from_authreq(radlast *rl, AUTH_REQ *authreq){ int status_type = 0; time_t crt_time; VALUE_PAIR *pair; int vj = 0; crt_time = time(NULL); if (!rl || !authreq || !authreq->request) return -1; pair = authreq->request; memset(rl, 0, sizeof(radlast)); rl->ut_time = crt_time; while (pair != (VALUE_PAIR *)NULL) { switch (pair->attribute) { case PW_ACCT_STATUS_TYPE: status_type = pair->lvalue; break; case PW_USER_NAME: strncpy(rl->login, (char *)pair->strvalue, sizeof(rl->login)); break; case PW_CLIENT_PORT_ID: rl->ent.port = pair->lvalue; break; case PW_FRAMED_ADDRESS: case PW_LOGIN_HOST: rl->client_ip = pair->lvalue; break; case PW_ACCT_SESSION_TIME: rl->length = pair->lvalue; rl->ut_time -= pair->lvalue; break; case PW_ACCT_INPUT_OCTETS: rl->inb = pair->lvalue; break; case PW_ACCT_OUTPUT_OCTETS: rl->outb = pair->lvalue; break; case PW_CLIENT_ID: rl->nas_ip = pair->lvalue; break; case PW_NAS_PORT_TYPE: rl->ent.port_type = pair->lvalue; break; case PW_LOGIN_SERVICE: switch ((int)(pair->lvalue)) { case PW_TELNET: rl->ent.proto = P_TELNET; break; case PW_RLOGIN: rl->ent.proto = P_RLOGIN; break; case PW_TCP_CLEAR: rl->ent.proto = P_TCP_CLEAR; break; case PW_PORTMASTER: rl->ent.proto = P_PORTMASTER; break; default: rl->ent.proto = P_LOGIN_UNK; } break; case PW_FRAMED_PROTOCOL: switch ((int)(pair->lvalue)) { case PW_PPP: rl->ent.proto = P_PPP; break; case PW_SLIP: rl->ent.proto = P_SLIP; break; default: rl->ent.proto = P_FRAMED_UNK; } break; case PW_ACCT_DELAY_TIME: rl->ut_time -= pair->lvalue; break; case PW_FRAMED_COMPRESSION: vj++; break; case PW_ACCT_TERMINATE_CAUSE: rl->ent.term_cause = pair->lvalue; break; case PW_ACCT_CALLED_STATION_ID: strncpy(rl->calledid,(char*)pair->strvalue, sizeof(rl->calledid)); break; case PW_ACCT_CALLING_STATION_ID: strncpy(rl->callingid,(char*)pair->strvalue, sizeof(rl->callingid)); break; /* Next attributes are VSAs */ case PW_ACCT_ASCEND_DATA_RATE: rl->rxrate = pair->lvalue; break; case PW_ACCT_ASCEND_XMIT_RATE: rl->txrate = pair->lvalue; break; case PW_CONNECT_INFO_OLD: rl->txrate = (UINT4)atol(pair->strvalue); rl->rxrate = rl->txrate; break; case PW_ACCT_USR_CONNECT_SPEED: rl->rxrate = rl->txrate = usr_speeds[pair->lvalue%54 - 1]; break; case PW_CONNECT_INFO: sscanf(pair->strvalue,"%d/%d%*s",&rl->txrate,&rl->rxrate); break; }; pair = pair->next; }; if ((rl->ent.proto == P_SLIP) && vj) rl->ent.proto = P_CSLIP; return status_type;}/* * Updates the user entry from the user_stats databse (add one more login
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -