📄 radwatch.c
字号:
* as restricted time for this user, count that time in... */static void update_user_time(radlast rl){ USER_TIME *ut; int t; t = strlen(rl.login); if (!t || (t > USERNAME_MAX)) return; /* avoid invalid data */ ut = user_time_head; while (ut != NULL) { if (strcmp(ut->username, rl.login) == 0) { /* found on list */ struct period u_time; u_time.start = rl.ut_time - rl.length; u_time.end = rl.ut_time; /* add this to this user ... */ ut->counted += common_time(ut->period, u_time); } ut = ut->next; } return;}/* * get_user_time * returns the used time by the user withing a certain frame period */static int parse_radacct_file(void){ int fd; char filename[PATH_MAX]; radlast rad_last; memset(filename, 0, sizeof(filename)); if (!monthly_detail) sprintf(filename, "%s/%s", rad_acctdir, RADIUS_LAST); else { time_t crt_time; struct tm *time_info; crt_time = time(NULL); time_info = localtime(&crt_time); sprintf(filename, "%s/%d/%s-%02d", rad_acctdir, 1900+time_info->tm_year, RADIUS_LAST, time_info->tm_mon + 1); } fd = open(filename, O_RDONLY); if (fd < 0) return -1; if (debug_flag) { printf("Parsing radlast (%s) file: ", filename); fflush(stdout); } memset(&rad_last, 0, sizeof(radlast)); /* okay, start reading the radlast log file */ while(read(fd, &rad_last, sizeof(radlast)) == sizeof(radlast)) { update_user_time(rad_last); memset(&rad_last, 0, sizeof(rad_last)); } /* done reading radlast logging info */ close(fd); if (debug_flag) { printf("OK.\n"); fflush(stdout); } return 0;}/* * Print a short (and hopefully clear) usage screen. */static void radwatch_usage(void){ printf("\n%s version %s\n", progname, REVISION); printf("Usage: %s <option>\nValid options are:\n", progname); printf("\t-a\t\taccounting dir for radiusd\n"); printf("\t-d\t\tconfiguration dir for radiusd\n"); printf("\t-h\t\toutput this help screen\n"); printf("\t-m\t\tuse the monthly status files created by radiusd\n"); printf("\t-x\t\tenable debugging\n"); printf("\nNOTE: all these flags should match the flags currently in use\n"); printf(" by radiusd daemon.\n");}/* * Open the radlist database for the current month. The algorithm will * fail at the end of the month, but this will be fixed in a future * release (if the period wraps around midnight - end < start - we * won't be able to read the last month statistics. Hopefully no one * will be hurt so bad at this stage.... */static GDBM_FILE open_radlist(void){ GDBM_FILE dbf; char db_name[PATH_MAX]; int month; time_t crt_time; struct tm *time_info; crt_time = time(NULL); time_info = localtime(&crt_time); month = time_info->tm_mon + 1; sprintf(db_name, "%s/%d/%s", rad_acctdir, 1900+time_info->tm_year,RADIUS_USER_STATS); if (debug_flag) printf("Using database file %s ...\n", db_name); dbf = gdbm_open(db_name,0,GDBM_READER, 0600,NULL); if (dbf == NULL) fprintf(stderr, "Error opening the radlist (%s) database.\n",db_name); return dbf;}/* * Well, this programs accepts arguments and flags... * Isn't it cool ? :-) */static void parse_args(int argc, char **argv){ int flag; while ((flag = getopt(argc, argv, "ma:d:xh")) != EOF) { switch (flag) { case 'm': monthly_detail++; break; case 'a': rad_acctdir = optarg; break; case 'd': radius_dir = optarg; break; case 'h': radwatch_usage(); exit(0); case 'x': debug_flag++; break; default: radwatch_usage(); exit(-1); } } return;}/* * check the timerestriction for a certain user * * return: * 0 = okay * < 0 = time exceeded */static void insert_user_in_list(char *username, struct time_frame *tf, time_t when, int max_seconds, user_entry *ue, int ue_size){ int usr_time = 0; struct period period; int present_entries; int i; if (!username || !strlen(username)) return; /* build the start time and the end time for the frame period */ get_period(&period, tf, when); /* if this use is logged in ... */ present_entries = (ue_size - sizeof(user_entry))/sizeof(port_entry); /* be safe */ present_entries = min(present_entries, (unsigned int)ue->logins); for (i=0; i < present_entries; i++) { port_entry *pe_tmp; struct period u_time; pe_tmp = (port_entry *)((char *)ue + sizeof(user_entry)) + i; u_time.start = pe_tmp->time; u_time.end = when; if (u_time.end < u_time.start) /* non-sense - claculating for the past... */ continue; usr_time += common_time(period, u_time); } add_user_time_list(username, period, max_seconds, usr_time);}/* * Opens the radius stop list file, in the mode supplied by argument. * Returns the result of the call to fopen */static FILE *open_radstop_file(const char * mode){ FILE *fp; char filename[PATH_MAX]; sprintf(filename, "%s/%s", radius_dir, RADIUS_STOP); fp = fopen(filename, mode); return fp;}/* * Returns true if the account is locked. * used by the lock_accounts function. */static int is_locked(char *user){ FILE *fp; char buffer[1024]; fp = open_radstop_file("r"); if (fp == NULL) { /* file not found, account is no locked */ return 0; } while (fgets(buffer, sizeof(buffer), fp) != NULL) { if (strlen(buffer) == 0) continue; buffer[strlen(buffer)-1] = '\0'; if (strcmp(user, buffer) == 0) { fclose(fp); return 1; } } return 0; /* default: not locked */}/* * This function adds the supplied user at the end of the radius stop file * No checking for the previous existence in that file is done since this * test is supposed to be already done somewhere else */static void lock_account(char *user){ FILE *fp; fp = open_radstop_file("a"); if (fp == NULL) { /* very odd error */ fprintf(stderr, "Could not open/creat the radius stop list file !\n"); exit(-3); } fprintf(fp, "%s\n", user); fclose(fp);}/* * Iterate through the user list and check for over-quota accounts. If it * is not already locked, lock the account. */static void lock_accounts(void){ USER_TIME *ut; ut = user_time_head; while (ut != NULL) { if (ut->restriction > ut->counted) { ut = ut->next; continue; } printf("%s\n", ut->username); /* this account needs to be locked out */ if (is_locked(ut->username)) { ut = ut->next; continue; } lock_account(ut->username); ut = ut->next; }}/* * Given an user, walks through the user_time list and see if this * user is over quota. */static int over_quota(char *user){ USER_TIME *ut; ut = user_time_head; while (ut != NULL) { if (strncmp(ut->username, user, USERNAME_MAX) == 0) /* our account */ if (ut->restriction < ut->counted) return 1; ut = ut->next; } return 0;}/* * Verify each account listed in radiusd stop list to see if it * still match the restriction time criteria. If it does NOT, then * this user should not be black-listed anymore... */static void unlock_accounts(void){ FILE *fo, *fn; char fileold[PATH_MAX], filenew[PATH_MAX]; char buffer[1024]; sprintf(fileold, "%s/%s", radius_dir, RADIUS_STOP); sprintf(filenew, "%s/%s.new", radius_dir, RADIUS_STOP); fo = fopen(fileold, "r"); if (fo == NULL) { /* no stoplist, bail out */ if (debug_flag) { printf("!!!"); fflush(stdout); } return; } fn = fopen(filenew, "w"); if (!fn) { fprintf(stderr, "Error creating file %s (permission problem ?)\n", filenew); exit(-3); } while (fgets(buffer, sizeof(buffer), fo) != NULL) { if (buffer[strlen(buffer)-1] != '\n') { /* line too long ... */ fprintf(stderr, "line too long reading from %s\n", fileold); fclose(fn); fclose(fo); exit(-3); } if (strlen(buffer) > USERNAME_MAX) { /* not a username line */ fprintf(fn, "%s", buffer); if (debug_flag) { printf("!-!-!"); fflush(stdout); } continue; } buffer[strlen(buffer)-1] = '\0'; if (over_quota(buffer)) /* this user is still over quota */ fprintf(fn, "%s\n", buffer); else if (debug_flag) { printf("%s ", buffer); fflush(stdout); } /* else will be skipped */ } fclose(fo); fclose(fn); unlink(fileold); link(filenew, fileold); unlink(filenew);} /* * Just to be fancy and put two calls to other functions in their own block... * Overall, this is the idea of this program: unlock the accounts which are * no longer under quota constraints, and add the new ones after that. */static void check_user_times(void){ if (debug_flag) print_user_list(); if (debug_flag) { printf("Unlocking accounts no longer over quota: "); fflush(stdout); } unlock_accounts(); if (debug_flag) printf("DONE. \n"); if (debug_flag) { printf("Locking accounts over quota: "); fflush(stdout); } lock_accounts(); if (debug_flag) printf("DONE.\n");}/* * The Main Thing: make this program work. */int main(int argc, char ** argv){ GDBM_FILE dbf; datum key, content, nextkey; time_t crt_time; /* init paramaters */ progname = argv[0]; monthly_detail = 0; rad_acctdir = RADACCT_DIR; radius_dir = RADIUS_DIR; radius_log = NULL; parse_args(argc, argv); crt_time = time(NULL); /* by default check against current time */ dbf = open_radlist(); if (dbf == NULL) exit(-1); if (debug_flag) { printf("Building preliminary list of users: "); fflush(stdout); } key = gdbm_firstkey(dbf); while (key.dptr != NULL) { static char str_user[1024]; struct conf_line *pp; struct tm *tm; short dtime; int i; /* init those each time for safety */ memset(str_user, 0, sizeof(str_user)); memcpy(str_user, key.dptr, min(key.dsize, sizeof(str_user)-1)); /* * The current time is converted to HHMM format for * comparision against the time values in the TTY entry. */ tm = localtime(&crt_time); dtime = tm->tm_hour * 100 + tm->tm_min; content = gdbm_fetch(dbf, key); if (content.dptr == NULL) { fprintf(stderr, "Can not retrieve data for user %s\n",str_user); nextkey = gdbm_nextkey(dbf,key); free(key.dptr); key=nextkey; continue; } /* * Try to find a matching entry for this user. Default to * letting the user in - there are pleny of ways to have an * entry to match all users. */ if ((pp = get_user_line (str_user)) == NULL) { /* no restriction */ nextkey = gdbm_nextkey(dbf,key); free(key.dptr); key=nextkey; continue; } if (pp->times == 0) { /* * The entry is there, but has no time entries */ nextkey = gdbm_nextkey(dbf,key); free(key.dptr); key=nextkey; continue; } /* * Each time entry is compared against the current * time. For entries with the start after the end time, * the comparision is made so that the time is between * midnight and either the start or end time. */ for (i = 0; pp->times[i].t_start != -1; i++) { if (! (pp->times[i].t_days & PORT_DAY(tm->tm_wday))) continue; if (pp->times[i].t_start <= pp->times[i].t_end) { if (dtime >= pp->times[i].t_start && dtime <= pp->times[i].t_end) insert_user_in_list(str_user, pp->times+i, crt_time, pp->restriction, (user_entry *)content.dptr, content.dsize); } else { if (dtime >= pp->times[i].t_start || dtime <= pp->times[i].t_end) insert_user_in_list(str_user, pp->times+i, crt_time, pp->restriction, (user_entry *)content.dptr, content.dsize); } } nextkey = gdbm_nextkey(dbf,key); free(key.dptr); key=nextkey; } gdbm_close(dbf); if (debug_flag) { printf("OK.\n"); fflush(stdout); } if (parse_radacct_file() != 0) fprintf(stderr, "Unable to open radlast log file !\n"); else check_user_times(); empty_user_time_list(); exit(0);}void rad_exit(int code){ exit(code);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -