⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 radwatch.c

📁 This program is a RADIUS RFC-compliant daemon, which is derived from original Livingston Enterprise
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 1999-2002 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. *//* * RADWATCH * * This program is intened to be run from cron every N minutes (were * N >= 5) to enforce user login limits between certain hours of the * day. Curently only times which DO NOT WRAP at midnight are known  * to work, although theoretically the code is able to handle that * case too. * * This program is intended to be used in conjunction with pm_kill * program. On normal usage, it will output a list of users which * have exceeded their quota (if any) during the time of the  * restriction period. * * For usage examples, check the supplied radwatch.conf file  * distributed with this release. */static char rcsid[] = "$Id: radwatch.c,v 1.6.4.2 2004/08/27 21:45:16 flovergine Exp $";#include "yard.h"#define REVISION    "$Revision: 1.6.4.2 $"#define RADWATCH   "radwatch.conf"	/* radwatch config file */#ifndef min#define min(a,b) ((a)<(b)?(a):(b))#endif#ifndef max#define max(a,b) ((a)>(b)?(a):(b))#endif/* * PORT_IDS - Allowable number of IDs per entry. * PORT_TTY - Allowable number of TTYs per entry. * PORT_TIMES - Allowable number of time entries per entry. * PORT_DAY - Day of the week to a bit value (0 = Sunday). */#define	PORT_IDS	64#define	PORT_TTY	64#define	PORT_TIMES	24#define	PORT_DAY(day)	(1<<(day))int debug_mem=0;/* *	pt_names - pointer to array of device names in /dev/ *	pt_users - pointer to array of applicable user IDs. *	pt_times - pointer to list of allowable time periods. */struct	conf_line	{    long        restriction;    char	**users;    struct	time_frame  *times;};struct period {    time_t start;    time_t end;};typedef struct user_time {    int  restriction;    int  counted;    char username[USERNAME_MAX];    struct period period;    struct user_time *next;} USER_TIME;static FILE	*ports;static int      monthly_detail;const char      *progname = NULL;const char      *radius_dir = NULL;const char      *rad_acctdir = NULL;const char      *radius_log = NULL;int             debug_flag = 0;static USER_TIME *user_time_head = NULL;#if defined(SUN)	extern char *optarg;#endif /* Inserts a new entry into the linked list of the known users. The space is *//* malloced and should be free'd later (using empty_user_time_list()) */static void add_user_time_list(char *username, struct period period, int restriction, int counted){    USER_TIME *ut;    ut = user_time_head;    while (ut != NULL) {	if ((strcmp(ut->username, username) == 0) &&	    (ut->period.start == period.start) &&	    (ut->period.end == period.end))	    /* already on list */	    return;	ut = ut->next;    }    ut = (USER_TIME *)malloc(sizeof(USER_TIME));    if (ut == NULL) {	fprintf(stderr, "malloc error - out of memory\n");	exit(-2);    }    memset(ut, 0, sizeof(USER_TIME));    strncpy(ut->username, username, USERNAME_MAX);    ut->restriction = restriction;    ut->counted = counted;    ut->period.start = period.start;    ut->period.end = period.end;    ut->next = user_time_head;    user_time_head = ut;}    	/* This function traverse the linked list of the known users and free() *//* the space used by it's elements. */static void empty_user_time_list(void){    USER_TIME *ut;        ut = user_time_head;    if (ut == NULL)	return;    while (ut->next != NULL) {	USER_TIME *temp;	temp = ut->next;	free(ut);	ut = temp;    }}/* Open the configuration file */static void open_conf_file(void){    static char filename[PATH_MAX];    if (ports)	rewind (ports);    else {	memset(filename, 0, sizeof(filename));	sprintf(filename, "%s/%s", radius_dir, RADWATCH);	ports = fopen(filename, "r");    }}/* Close the configuration file */static void close_conf_file(void){    if (ports)	fclose (ports);        ports = (FILE *) 0;}/* Reads and parses the next valid config line from the program's *//* configuration file. All the data it returns it is statically *//* allocated, no need to be free'd. The parser _should_ work... */static struct conf_line *get_conf_line(void){    static	struct	conf_line  conf_line;	/* static struct to point to         */    static	char	buf[BUFSIZ];	/* some space for stuff              */    static	char	*users[PORT_IDS+1]; /* some pointers to user ids     */    static	struct	time_frame times[PORT_TIMES+1]; /* time ranges         */    char	*cp;			/* pointer into line                 */    int	dtime;			/* scratch time of day               */    int	i, j;    /*     * If the ports file is not open, open the file.  Do not rewind     * since we want to search from the beginning each time.     */    if (! ports)	open_conf_file();    if (! ports) {	fprintf(stderr, "Can not open configuration file (%s/%s).\n",		radius_dir, RADWATCH);	exit(-1);    }    /*     * Common point for beginning a new line -     *     *	- read a line, and NUL terminate     *	- skip lines which begin with '#'     *	- parse off a list of user names     *  - parse off the restriction value     *	- parse off a list of days and times     */    for(;;) {	/*	 * Get the next line and remove the last character, which	 * is a '\n'.  Lines which begin with '#' are all ignored.	 */	if (fgets (buf, sizeof(buf), ports) == 0)	    return NULL;	if (buf[0] == '#')	    continue;	buf[strlen (buf) - 1] = 0;	cp = buf;	/*	 * Get the list of user names.  It is the first colon	 * separated field, and is a comma separated list of user	 * names.  The entry '*' is used to specify all usernames.	 * The last entry in the list is a (char *) 0 pointer.	 */	conf_line.users = users;	conf_line.users[0] = cp;	for (j = 1; *cp != ':'; cp++) {	    if (*cp == ',' && j < PORT_IDS) {		*cp++ = 0;		conf_line.users[j++] = cp;	    }	}	conf_line.users[j] = 0;	if (*cp != ':') /* line format error */	    continue;	*cp++ = '\0';	/* Get the restriction time. Next item should be an int */	if (!isdigit(*cp))	    /* line format error */	    continue;	else {	    long restriction;	    char **endptr = (char **) &cp;	    restriction = strtol(cp, endptr, 10);	    if ((restriction == 0) && (*endptr == cp)) /* no chars read */		continue;	    conf_line.restriction = restriction;	    cp = *endptr;	}	if (*cp != ':') /* line format error */	    continue;	*cp++ = '\0';	/*	 * Get the list of valid times.  The times field is the third	 * colon separated field and is a list of days of the week and	 * times during which this port may be used by this user.  The	 * valid days are 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', and 'Sa'.	 *	 * In addition, the value 'Al' represents all 7 days, and 'Wk'	 * represents the 5 weekdays.	 *	 * Times are given as HHMM-HHMM.  The ending time may be before	 * the starting time.  Days are presumed to wrap at 0000.	 */	if (*cp == '\0') {	    /* This kind of limit apply to every day, all hours */	    conf_line.times = 0;	    return &conf_line;	}	conf_line.times = times;		/*	 * Get the next comma separated entry	 */	for (j = 0;*cp && j < PORT_TIMES;j++) {	    /*	     * Start off with no days of the week	     */	    conf_line.times[j].t_days = 0;	    /*	     * Check each two letter sequence to see if it is	     * one of the abbreviations for the days of the	     * week or the other two values.	     */	    for (i = 0; cp[i] && cp[i+1] && isalpha (cp[i]); i += 2) {		switch ((cp[i] << 8) | (cp[i+1])) {		    case ('S' << 8) | 'u':			conf_line.times[j].t_days |= Su_DAY;			break;		    case ('M' << 8) | 'o':			conf_line.times[j].t_days |= Mo_DAY;			break;		    case ('T' << 8) | 'u':			conf_line.times[j].t_days |= Tu_DAY;			break;		    case ('W' << 8) | 'e':			conf_line.times[j].t_days |= We_DAY;			break;		    case ('T' << 8) | 'h':			conf_line.times[j].t_days |= Th_DAY;			break;		    case ('F' << 8) | 'r':			conf_line.times[j].t_days |= Fr_DAY;			break;		    case ('S' << 8) | 'a':			conf_line.times[j].t_days |= Sa_DAY;			break;		    case ('W' << 8) | 'k':			conf_line.times[j].t_days |= Wk_DAY;			break;		    case ('A' << 8) | 'l':			conf_line.times[j].t_days |= Al_DAY;			break;		    default:		    			return NULL; /* syntax error, can't continue ... */		}	    }		    /*	     * The default is 'Al' if no days were seen.	     */		    if (i == 0)		conf_line.times[j].t_days = Al_DAY;		    /*	     * The start and end times are separated from each	     * other by a '-'.  The times are four digit numbers	     * representing the times of day.	     */	    for (dtime = 0; cp[i] && isdigit (cp[i]); i++)		dtime = dtime * 10 + cp[i] - '0';	    if (cp[i] != '-' || dtime > 2400 || dtime % 100 > 59)		continue;	    conf_line.times[j].t_start = dtime;	    cp = cp + i + 1;	    for (dtime = i = 0; cp[i] && isdigit (cp[i]); i++)		dtime = dtime * 10 + cp[i] - '0';	    if ((cp[i] != ',' && cp[i]) ||		dtime > 2400 || dtime % 100 > 59)		continue;	    conf_line.times[j].t_end = dtime;	    cp = cp + i + 1;	}	/*	 * The end of the list is indicated by a pair of -1's for the	 * start and end times.	 */	conf_line.times[j].t_start = conf_line.times[j].t_end = -1;	return &conf_line;    }    return NULL; /* NOT REACHEAD... */}int unix_group(const char *name, const char *group){    struct passwd       *pwd;    char                **gr_mem;    struct group        *gr_ent;    /* Get encrypted password from password file */    if((pwd = getpwnam(name)) == NULL) {	debug("unix_group: getpwnam for <%s> failed\n", name);	return(0);    }    if((gr_ent = getgrnam(group)) == NULL) {	debug("unix_group: getgrnam(%s) for <%s> failed\n", group,name);	return(0);    }    /* Check the immediate group */    if(pwd->pw_gid == gr_ent->gr_gid) {	return(1);    }    /* Search for this user */    gr_mem = gr_ent->gr_mem;    while(*gr_mem != NULL) {	if(strcmp(*gr_mem, name) == 0) {	    return(1);	}	gr_mem++;    }    return(0);}/* * get_user_line - get ports information for user and tty * *	get_user_line() searches the conf file for an entry with a *	user field which match the supplied user name. The file is *      searched from the beginning, so the entries are treated as *      an ordered list. */static struct conf_line *get_user_line (const char *user){    int i;    struct	conf_line	*conf_line;    open_conf_file();    while ((conf_line = get_conf_line()) != NULL) {	if (conf_line->users == NULL)	    continue;	for (i = 0; conf_line->users[i]; i++) {	    /* is this a group name ? */	    if (conf_line->users[i][0] == '@')		if (unix_group(user, (conf_line->users[i])+1))		    break;	    /* now test if this is an username */	    if (strcmp(user, conf_line->users[i]) == 0 ||		strcmp(conf_line->users[i], "*") == 0)		break;	}	if (conf_line->users[i] != 0)	    break;    }    close_conf_file();    return conf_line;}/* * given to time frames, return the amount in secs for the common * period */static int common_time(struct period time1, struct period time2){    time_t t1, t2;    if (time1.end < time2.start)	return 0;    if (time1.start > time2.end)	return 0;    t1 = max(time1.start, time2.start);    t2 = min(time1.end, time2.end);    return (int)(t2 - t1);}static int get_period(struct period *period,struct time_frame *tf,time_t when){    struct tm *tm;    time_t zerotime;    zerotime = when;    tm = localtime(&zerotime);    zerotime -= tm->tm_hour*3600 + tm->tm_min*60 + tm->tm_sec;    period->start = period->end = zerotime;    period->start += (tf->t_start/100)*3600 + (tf->t_start%100)*60;    period->end   += (tf->t_end/100)*3600   + (tf->t_end%100)*60;    /* check for time wrap ... */    if (tf->t_start >= tf->t_end) {	/* time is wrapping accross 0 */	if (when >= period->start)	    /* current time passed start_time, 	     * end_time will be tomorrow */	    period->end += 24*3600;	else if (when <= period->end)	    /* current time before end time, start_time	     * was yesterday */	    period->start -= 24*3600;	else /* some other horror */	    return -1;    }    return 0;}/*  * This is a debugging function. It prints out the list of the users, * along with their time and quota. */static void print_user_list(void){    USER_TIME *ut;     printf("List of known users (%p): (user:quota:in_use):\n",	   user_time_head);    fflush(stdout);    ut = user_time_head;    while (ut != NULL) {	printf("\t%12s:%5d:%5d\n",	       ut->username, ut->restriction, ut->counted);	fflush(stdout);	ut = ut->next;    }    printf("\n");}/* * Given an entry from the radlast log file, check to see if the user * having that entry is a valid user in our linked list, and if it is * and the time of the entry matches the window time period recorded

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -