pax_global_header00006660000000000000000000000064140127507460014520gustar00rootroot0000000000000052 comment=c6c09b251264472d47c5f025901d4d1958ce0238 autolog-0.42/000077500000000000000000000000001401275074600131175ustar00rootroot00000000000000autolog-0.42/.gitignore000066400000000000000000000000411401275074600151020ustar00rootroot00000000000000# ignore made executable autolog autolog-0.42/CHANGES000066400000000000000000000061321401275074600141140ustar00rootroot00000000000000CHANGES(autolog): ================ - 0.2: Added 'hard' logout feature. Several bug fixes. - 0.21: Added 'pre-clear' option. - 0.30: Rewrote the configuration file parser. Added group matching and the "nowarn" option. Rewrote/cleaned up almost the whole program. - 0.31: Fixed bug with searching for group. If the group could not be found from the username, the program would segmentation fault. Hopefully fixed. - 0.32: re_exec seems to have a bug that dumps core in some cases. I rewrote the pat_match routine to not use it. Both versions of pat_match are included with an #ifdef. - 0.33: Nov 1996 Kyle Bateman Fixed bug in logging routine. When writing to log file, the program could crash. Also more careful check for non-existent processes. - 0.34: Dec 1996 Kyle Bateman Added man pages (thanks to Christoph Lameter). Some login processes didn't twiddle the "last access" time when a user first logged in. Checked to see if last access was older than login time to rule out such problems. - 0.35: Oct 1998 Kyle Bateman fixed segfault error (Thanks to Thomas Gray). fclose(log) was being called even when the logfile hadn't been opened. - 0.40: April 2000 Carsten Juerges Rewritten parts of the code to chase users and to make sure, they get the information about their approaching end. April 14, 2000 Detected some old(?) ps-commands which do not support the parameters, I used. rewritten this part and enabled a feature to pass any strange ps-command via config-file. April 28, 2000 Checked README-file and the manual-entries to make sure one will find information about all the new features. Added a little feature "nolostkill" to stop this program from killing lost processes. Only lost processes with uid (user-id) between 500 and 60000 will be killed, others usually belong to system processes. - 0.41: May 2020 James Dingwall Merge patches carried by debian which are not related to packaging: - 01_Makefile.patch - 02_autolog.patch - 04_check_ps_output.patch - 05_Fix-spelling-errors.patch - 06_adjust_makefile.patch - 07_clang-ftbfs.patch - 08_trailing_whitespace.patch Reformat the autolog.c source to for a more consistent style: - consistent tabbed indent instead of whitespace mix - insert spaces around operators for better readability - consistent brace usage for if/then/else etc Squash some warnings reported by gcc (gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0) User id range checking adjusted to suit debian and systems where valid user accounts may have a uid >60000. Improvements in string length handling: - Use utmp #defines UT_NAMESIZE and UT_LINESIZE for string lengths in userdata struct - Use 'n' versions of strcpy / strcmp / sprintf - Use a default ps command which prints usernames to 32 chars - 0.42: February 2021 James Dingwall Nominate myself as the maintainer of autolog. Zynstra uses autolog and have an interest in seeing the package maintained. autolog-0.42/Makefile000066400000000000000000000014661401275074600145660ustar00rootroot00000000000000# ********************************************************* # Change this section as needed # The -g flag is to include debugging information. It gets # stripped back out in the install command anyway. CC ?= gcc #CFLAGS += -g MANDIR = $(DESTDIR)/usr/share/man BINDIR = $(DESTDIR)/usr/sbin/ STATEDIR = $(DESTDIR)/var/lib/autolog/ CONFDIR = $(DESTDIR)/etc/ INIDIR = $(DESTDIR)/etc/init.d/ # ********************************************************* autolog: autolog.c $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o autolog autolog.c install: autolog install -d $(BINDIR) $(INIDIR) $(CONFDIR) $(STATEDIR) $(LOGDIR) $(MANDIR) install -m744 -o 0 -g 0 autolog $(BINDIR) # install -m744 -o 0 -g 0 autolog.init $(INIDIR)/autolog install -m644 -o 0 -g 0 autolog.conf $(CONFDIR) clean: rm -f autolog autolog-0.42/README000066400000000000000000000352151401275074600140050ustar00rootroot00000000000000Autolog 0.42 James Dingwall as maintainer Autolog 0.41 The source was investigated after examining issues which occurred when accounts with long usernames (nss_winbind DOMAIN\user) would cause autolog to segfault. This revealed two key issues: - userdata string length < UT_NAMESIZE - ps output with truncated usernames did not match pids This revision updates string handling functions to use suitable 'n' variants, makes user and terminal variables use UT_NAMESIZE and UT_LINESIZE, changes the default ps command to output usernames to 32 characters to match UT_NAMESIZE; Autolog 0.40 Autolog is a new version of autolog by Kyle Bateman (kyle@actarg.com), modified by me (Carsten Juerges, juerges@cip-bau.uni-hannover.de) to get the logout-warning on that terminal I worked in, last time. Before the warning was written on the login-screen, where I started X (startx), so it was difficult to get or to react on this warning. Now it is checked, which is the terminal with the shortest idle-time and the message is displayed there. So I can react on it, there. I put the old readme-text below the (=====)-line and added my changes (of details) into that text. They can be found by searching for "##". Here I just want to report about a few changes, I added to the program. - first of all: This program can run in daemon-mode or as "ordinary program". As ordinary program it writes "/tmp/autolog.data" when starting. So it is not necessary to keep the program in memory to chase sleeping users. As this file is read, when the program starts. If this file doesn't exist, no problem. It will be generated next time. See the options. If running as daemon, make sure, you don't start it several times e.g. by crontab. If running as ordinary program, it will stay at least as long in memory until all necessary kickouts are done. And some more time to make sure, user doesn't return 2 minutes later. (Until als bans are over.) - if a user logs out, before his session-limit is reached, his limit will be reset. It was also possible to log in again, after being kicked out. -> fixed this. added a ban-time. (##-1) the session-limit will be reset when the banning has passed or a bit later, depends on when the daemon wakes up from sleeping. -> added little feature that kills forgotten processes. they do appear (e.g. netscape) when a user does not terminate netscape correctly. -> daemon tries to wake up a sleeping user by beeping. the user also gets an email, his beeping might not work. Email might not work on a network, don't know, could only test this on one network, there it worked. -> being idle for too long is punished with 2 Mins ban. Users should not be punished for being idle they might be thinking about the current problem. They deserve a little break. These two minutes should only stop those user who log in again and again to block the computer. -> if the user tries to login before his ban-time ends, he will be kicked out without any warning. He will be banned for the originial ban-period, again :) -> changed the "exempt-code" to idle=-1, so idle=0 will be useful for demonstration-purpose. -> the information about crontab (down in the text) has expired, if running this program as daemon. left it, because i find the hints about crontabs quite useful. Maybe it is useful to restart the program from time to time as it might have halted due to any errors. (via cron) The program should only run once on a machine. Otherwise the resulting user-information about being kicked out it might be confusing. -> Make sure to reduce the size of the log-file from time to time, as it is always growing when adding messages. The logile or at least a part of it might be useful to find misconfiguration or even bugs in the program. ======================================================================= Autolog 0.35 Autolog is a version of autologout (idleout-mcm) modified by me to allow a more detailed configuration file, and to accept command line parameters. According to David Dickson, the code originally came from the "Wizard's Grabbag" from the May 1990 Unix World. He ported the code essentially unchanged. Mike Mitchell added some code to read a file "/etc/autologout.exempt" listing those users which should not be subject to auto logout. My system required a little more complex approach. I wanted some users to be logged off more aggressively than others. I wanted my own sessions to remain on line only if they existed on certain ports. I also wanted users coming in over the net to be subject to a little different idle time than other users. After doing version 0.20, several people wrote with various additions and patches. The problem was that the original syntax of the autolog.conf file was a bit limiting and it was hard to work in too many additional features without making a big fat mess. With the new, improved format of the configuration file, I should be able to accommodate many more future features. The configuration file consists of multiple lines, each of which describes a class of processes subject (or not subject) to a certain auto logout procedure. A line consists of any number of switches. Value switches are of the form: "name=value". Boolean switches are of the form: "name" or "noname". Here are some example lines: name=root line=tty[1-7] idle=0 name=guest idle=5 grace=60 nomail hard warn group=lynx-.* idle=10 grace=60 clear idle=60 grace=30 Using these switches, you can define a username, a group, and a tty line. These descriptions can contain wildcard characters (regular expressions). You can also define an idle time, a grace period and a few other options. When reading the configuration file, the program creates a record for each configuration line. A value is assigned to each variable in the record regardless of whether or not you specify one explicitly. Values for missing variables are provided by defaults which are compiled in and can be modified from the command line. If no configuration file is found, the program will create a single entry which has all values set from the defaults. This entry will match any process on any port (name=.+ line=.+ group=.+). Therefore, the default action is to kill all processes. The values which can be set for each entry are as follows: name= A regular expression specifying which username(s) to match. group= A regular expression specifying which group(s) to match. line= A regular expression specifying which tty line(s) to match. Omit the "/dev/" part of the special name. idle= An integer specifying the number of --minutes-- of idle (or connect) time to allow before beginning automatic logoff. An idle time of 0 exempts the process from automatic logoff. (##) changed this to "-1" => exempts idle-time. this allows short idle-time "0" for demonstrating. grace= An integer specifying the number of --seconds-- from the initial warning to killing the process. ban= An integer specifying the number of --minutes--, the user should stay away after exceeding his session-limit. (##-1) hard A boolean value indicating total connect time will be considered rather than idle time. mail A boolean value indicating that mail will be sent to the user explaining that he was killed. clear A boolean value indicating that the screen will be cleared before a warning message is sent. (##) -> will only be cleared, if user is still on that screen. warn A boolean value indicating that a warning message will be sent at the beginning of the "grace" period. log A boolean value indicating that activities will be logged to the logfile (if it exists). Additionally I added a feature for exotic ps-versions: ps=ps -ef a ps-command, which results in one heading line and lines starting with username and pid e.g. "ps=ps aux" on SuSE Linux. lostkill A boolean value indicatin whether this program should kill lost processes or not. So place "nolostkill" in the config-file doesn't touch them. If enabled(default), this program will only kill lost processes with uid between 500 and 60000. Other uids (at least in some Linux dialects) belong to system processes which should not be killed. Once configured, the program reads the utmp file, entry by entry. The username for each 'user process' is compared to the entries in the configuration file. The first entry to match both the name, the group, and the tty line of the process will be used to conduct the automatic logout. If no entries are found matching a given process, that process will be spared from an untimely demise. Therefore, it is a good idea to always have a "cleanup" line at the end of the configuration file to catch anything that might have been missed by the more explicit definitions. Since the default name, group, and line are all ".+", a simple line like: idle=30 will do. Actually, any one switch can be specified on the line and all the others will get the default values. See the sample file autolog.conf for an example configuration. Installation Instructions: 1. If desired, edit the defaults in autolog.c such as D_IDLE, D_GRACE, D_MAIL, etc. (This is generally not necessary). If you want the binary to land somewhere besides /usr/sbin, edit the Makefile accordingly. 2. Type 'make install'. 3. Copy autolog.conf to /etc and then edit it to make the changes needed by your system. (See the instructions above.) 4. Wait until the system has a bunch of idle processes. Run "autolog -d -n |less" and examine the output to see that the desired processes are going to "get the axe." If it looks good, try running "autolog -d" to make sure. When you're happy with your configuration file, setup cron. 5. In your Crontab file place a line that invokes autolog about every few minutes, such as: 0,10,20,30,40,50 * * * * /usr/sbin/autolog On my system cron only runs the process at night. This way, users sessions stay on uninterrupted during the workday. I use the lines: 0 20 * * * /usr/sbin/autolog 0 22 * * * /usr/sbin/autolog 0 1 * * * /usr/sbin/autolog COMMAND LINE PARAMETERS: -a (all processes) Print information on ALL utmp entries--not just user processes. -d (debug mode) This is helpful in setting up your configuration file. The program runs in foreground rather than forking and it prints out verbose messages about what it is doing. -n (nokill) Use this to prevent autolog from actually "killing" anyone. Use -d and -n together when setting up a new configuration file. -o (ordinary) Use this to start the program as ordinary program. Otherwise it will stay as daemon in memory. Good idea if you are low on memory. -f config_file_name Use this to override the default: "/etc/autolog.conf" -l log_file_name Use this to override the default: "/var/log/autolog.log" Note that if this file doesn't exist, no logging will happen. Create the file (with touch) to enable logging. -t idle_time Use this to override the internal default idle time (minutes) -g grace_period Use this to override the internal default grace period (seconds) -m yes/no Use this to override the internal mailing switch. If "yes" the program will send mail to the users right after killing them. -c yes/no Use this to override the internal "pre-clear" switch. If "yes" the program will clear the terminal screen before warning the user. -w yes/no If set to "no" no warning message will be printed to processes about to be killed. -h yes/no Do timeouts based on total session time--not idle time. (hard) -L yes/no If set to "yes" activities will be written to the logfile if present. Bugs/Caveats: - The utmp file seems to only hold 8 characters worth of login name. If your login name is shorter than this, note that autolog may only see the first 8 characters. This is screwing up the group search function too. This shouldn't be too hard to fix. I'll just have to derive the real login name from the pid or something... - There is a feature that would be very helpful that autolog doesn't have yet. The ppp program generally creates a login process which is seen by autolog. The problem is that network activity does not change the idle time on the tty controlled by ppp. So there is no way (with the existing code) for autolog to know if the network link has gone idle for a period of time (it appears idle all the time--no matter what happens. So your choices are this: You can leave ppp out of your "autolog strategy" in which case it will look like an idle shell and will get killed. Or, you can put it in the configuration file with an exemption (idle=0) in which case it will never get killed no matter what. If someone knows where I can snoop in the OS (in a portable way) to find out how long its been since a ppp login passed any network traffic, I would add a ppp switch to be used for this purpose. - When this program get to another system, it sometime needs to be recompiled. I compiled it in SuSE 6.3 and running under SuSE 6.0 it gave a "segmentation fault" without recompiling. Ideas: - One might find out, how the "you have new mail"-message gets to the user and try to use this way for letting the user know about his coming end. - One might think about a pop-up box when running a session without any terminals. At the moment this program tries to send an email to the user. If one selects enough idle-time, this should be ok. - Maybe it is possible when this deamon starts sleeping, it actually terminates and gets started again after some time. This might save some memory when sleeping or sleeping for more than 5 Minutes. I assume, other deamons behave like this, too, but I don't know how... Have fun knocking off those 'delinquent' users! And don't let the power go to your head... Kyle Bateman kyle@actarg.com Be careful when playing with a daemon. Devils like playing, but only they know all rules of their games! A game, plaid with a devil becomes the devil's game. Users should be informed about such a program running. Especially users, which are kicked off without warning might get very angry when losing several hours of work. Keep in mind, some are running jobs over several hours. Carsten Juerges juerges@cip-bau.uni-hannover.de p.s. quoting a part of "man strtok" > BUGS Never use this function. This function modifies ... autolog-0.42/autolog.8000066400000000000000000000051221401275074600146620ustar00rootroot00000000000000.TH AUTOLOG 8 "Administrative Utilities" "Linux" \" -*- nroff -*- .SH NAME autolog \- Log out idle users .SH SYNOPSIS \fBautolog\fP [ \fBoptions\fP ] .br .SH DESCRIPTION The program reads the utmp file, entry by entry. The username for each 'user process' is compared to the entries in the configuration file (see .B autolog.conf(5) ). The first entry to match both the name, the group, and the tty line of the process will be used to conduct the automatic logout. .SH CALL .TP .B /etc/init.d/autolog start .PD 0 .TP or .TP .B autolog to run this program in daemon-mode .PD .TP .B autolog -o to run this program as "ordinary" program. Keep in mind: Also when running as ordinary program, it will stay in memory until all its jobs are done. .SH OPTIONS .TP .B -a (all processes) Print information on ALL utmp entries--not just user processes. .TP .B -d (debug mode) This is helpful in setting up your configuration file. The program runs in foreground rather than forking and it prints out verbose messages about what it is doing. .TP .B -n (nokill) Use this to prevent autolog from actually "killing" anyone. Use \-d and \-n together when setting up a new configuration file. ( This will not affect killing of lost processes. ) .TP .B -o (ordinary) Use this to run this program as ordinary program, not as daemon. Program will end, when its job is done. In this case, some data is kept in "/var/lib/autolog/autolog.data". This is read, when the program is called again. .TP .B -f config_file_name Use this to override the default: "/etc/autolog.conf" .TP .B -l log_file_name Use this to override the default: "/var/log/autolog.log". Note that if this file doesn't exist, no logging will happen. Create the file (with touch) to enable logging. .TP .B -t idle_time Use this to override the internal default idle time (minutes) .TP .B -g grace_period Use this to override the internal default grace period (seconds) .TP .B -m yes/no Use this to override the internal mailing switch. If "yes" the program will send mail to the users right after killing them. .TP .B -c yes/no Use this to override the internal "pre-clear" switch. If "yes" the program will clear the terminal screen before warning the user. .TP .B -w yes/no Do timeouts based on total session time--not idle time. (hard) .TP .B -l yes/no If set to "yes" activities will be written to the logfile if present. .SH AUTHOR Kyle Bateman (autolog 0.35), .PD 0 .TP James Dingwall .TP (autolog 0.41) .PD .PP This manual page was modified for \fBDebian\fP by Paul Telford autolog-0.42/autolog.c000066400000000000000000001155601401275074600147450ustar00rootroot00000000000000/** * version 0.41: James Dingwall */ /*****************************************************************************/ /* */ /* Programm: autolog.c C-Programm to log out sleeping users */ /* version 0.40 */ /* */ /* Autor: Carsten Juerges Erster Versuch: 06.04.2000 */ /* Kurze Wanne 1 Letztes Update: 28.04.2000 */ /* 30926 Seelze */ /* Germany send me a postcard, if you like. :) */ /* juerges@cip-bau.uni-hannover.de */ /* */ /* Rechner: AMD K6-2 SuSE Linux 6.3 */ /* */ /* Meldung: This version seems to worke quite good. */ /* */ /* Auftauchende Probleme, known problems / features: */ /* - a program without any login (e.g. start Netscape and log off ) */ /* will be kicked out as lost process. */ /* - to become not idle he has to type something into a terminal */ /* when in beeps somewhere. */ /* - some lines "//##" have to be adapted to your specific linux. */ /* maybe your ps has different options or a different output. */ /* - Looks quite dirty, should be beautified, sometimes :) */ /* */ /* Warning: */ /* - Keep in mind: Someone who is kicked off might lose some data. */ /* - This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /*****************************************************************************/ /* "@(#) autolog.c 0.34 Originally ported by David Dickson" Modified by Michael C. Mitchell, 15Oct94 Rewritten by Kyle Bateman, Nov94, Aug95 Adapted to my System, by Carsten Juerges, Apr 2000 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define D_IDLE 30 /* maximum idle time (minutes) */ #define D_GRACE 120 /* grace time (sec) for user reply */ #define D_HARD 0 /* consider connect time only */ #define D_MAIL 1 /* notify user by mail */ #define D_CLEAR 0 /* clear user terminal before warning */ #define D_WARN 1 /* warn user before killing */ #define D_LOG 1 /* log activity in logfile */ #define WARNING 1 /* a warning message */ #define LOGOFF 2 /* a log-off message */ #define NOLOGOFF 3 /* a log-off failure message */ #define ANGRY 4 /* a log-off user returned message */ #define IDLEPUNISH 5 /* punish idling-users message */ #define HUP_WAIT 20 /* time to wait after SIGHUP (in sec.) */ #define KILLWAIT 3 /* time to wait after SIGKILL (in sec.) */ #define Max_Sleep 1800 /* max. sleeping time for this daemon ;-) */ #define ChckSleep 90 /* check whether user logged in again */ #define Idle_Ban 120 /* punishment-time for idle users */ //#define HUP_WAIT 2 /* (demo / debug) */ //#define KILLWAIT 1 /* (demo / debug) */ //#define Max_Sleep 10 /* (demo / debug) */ //#define ChckSleep 10 /* (demo / debug) */ #define STRLEN 64 #define LINELEN 256 #define MAXCONF 512 /* maximum lines in config file */ typedef struct { /* Name of user. */ char Name[UT_NAMESIZE + 1]; /* Output device with the minimum idle-time */ char Device[UT_LINESIZE + 1]; /* "." serves as flag that user logged out, */ /* when chasing lost processes. */ uid_t UserID; /* to check whether user has changed */ int IdleTime; /* Minimum-time the user is idle */ int SessStrt; /* Starttime of the users session */ int Ban_Ends; /* Endtime of banning user this user */ int WarnEnds; /* End of grace-time (after warning). */ } userdata; /* e.g. 30 Mins after hardkick. */ struct utmp *utmpp; /* pointer to utmp file entry */ char delims[] = "\n\t "; /* valid delimiters in config file */ char anystrg[] = ".+"; /* matches anything */ int debug = 0; int resist = 1; /* 0=> ordin. program 1=> behave as daemon. */ int do_bite = 1; int listall = 0; char *confname = "/etc/autolog.conf"; char *logfname = "/var/log/autolog.log"; char *datfname = "/var/lib/autolog/autolog.data"; int g_idle = D_IDLE; int g_grace = D_GRACE; int g_hard = D_HARD; int g_mail = D_MAIL; int g_clear = D_CLEAR; int g_warn = D_WARN; int g_log = D_LOG; typedef struct conf { char *name; /* user name */ char *group; /* group name */ char *line; /* tty line */ int idle; /* minutes of idle time */ int grace; /* minutes of grace time */ int ban; /* ban user for ... minutes */ int hard; /* consider connect time only */ int mail; /* notify by mail */ int clear; /* clear screen before warn */ int warn; /* warn before kill */ int log; /* log actions to logfile */ } conf_el; conf_el c_arr[MAXCONF]; int sleeptime = Max_Sleep; /* maximum amount of time */ int sleep_max = Max_Sleep; /* to sleep for daemon. */ int c_idx = 0; int userfill = 0; /* different users found. */ int usermax = 0; /* current size of List. */ userdata* userlst; /* Store user-Data here. */ int ids_fill; int ids_max; int *ids_lst; time_t time(); /* they are used so often */ time_t pres_time; /* current time. */ time_t chck_pid = 0; /* don't check pids before ... */ int lostkill = 1; /* 1 => kill lost processes. */ char *ps_cmd; static int check_utmp(); static int show_results(); static int save_users(); static int load_users(); static int set_defs(int); static int eat_confile(); static int pat_match(char *, char *); static int check_idle(userdata *); static void get_PIDs(char *, char *); static int kill_PIDs(char *, char *); static int kill_HUP(int); static int kill_KILL(int); static int kill_Res(int); static int mesg(int, char *, char *, int, int, conf_el *); static int log_msg(char *); static int bailout(char *, int); static int lower_sleep(int); static int kill_lost_PIDs(); extern int main(int argc, char *argv[]) { int i; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch(tolower(argv[i][1])) { case 'r': resist = 1; break; /* debug */ case 'o': resist = 0; break; case 'a': listall = 1; break; case 'b': do_bite = 0;/* I got used to */ break; case 'd': debug = 1; break; case 'h': g_hard = 1; break; case 'n': do_bite = 0; break; case 'l': logfname = argv[++i]; break; case 'f': confname = argv[++i]; break; case 't': g_idle = atoi(argv[++i]); break; case 'g': g_grace = atoi(argv[++i]); break; case 'm': g_mail = (argv[++i][0] == 'y'); break; case 'c': g_clear = (argv[++i][0] == 'y'); break; case 'w': g_warn = (argv[++i][0] == 'y'); break; case 'L': g_log = (argv[++i][0] == 'y'); break; default: fprintf(stderr, "autologout: illegal switch: %s\n", argv[i]); } } else { fprintf(stderr, "autologout: illegal parameter: %s\n", argv[i]); } } /* for */ ps_cmd = "ps axo user:32,pid,tty"; time(&pres_time); /* get current time for log-file */ log_msg("Starting Service"); eat_confile(); /* read config file */ if (!debug) /* if not in debug mode, */ if (fork()) exit(0); /* the parent process exits here. */ // if (!debug && resist) /* if not in debug mode, */ // if (fork()) // exit(0); /* the parent process exits here. */ userfill = 0; usermax = 8; userlst = (userdata *)calloc(sizeof(userdata), 1 + usermax); load_users(); if (debug) { printf("\n"); printf("From the datafile:\n"); printf("==================\n"); show_results(); printf("Done reading datafile\n"); } /* now sit in an infinite loop and work */ do { time(&pres_time); /* get current time */ sleeptime = sleep_max; /* assume max. sleeptime. */ setutent(); if (debug) printf("\n"); while ((utmpp = getutent()) != (struct utmp *) NULL) check_utmp(); if (debug) show_results(); for (i = 1; i <= userfill; i++) { if (check_idle(&userlst[i]) == 2) { if (debug) printf("knock out.\n"); userlst[i] = userlst[userfill]; userfill--; } } /*.. check for lost processes, from time to time. ...........................*/ if (lostkill && pres_time>chck_pid) { if (debug) printf("check for dead processes.\n"); kill_lost_PIDs(); chck_pid = pres_time + 10 * 60; if (debug) printf("next check for processes after %10ld.\n", chck_pid); } if (debug) { //show_results(); printf("daemons maximum sleeptime %7d seconds, today.\n", sleep_max); printf("daemon is falling asleep for %5d seconds, now.\n", sleeptime); } if (resist || (sleeptime < sleep_max) ) sleep(sleeptime); } while (resist || /* Stay when in daemon-mode */ (sleeptime < sleep_max) ); /* or users are to be kicked off */ save_users(); log_msg("Stopped service"); } /*************************************************************** * This function makes sure we will find in our table: * * - shortest idle-time and device of this. * * - earliest start-time of all logins. * ***************************************************************/ static int check_utmp() { /* select utmp entries needing killing */ char dev[STRLEN], name[STRLEN], prname[STRLEN]; char *msg; char tmp_str[80]; struct stat status; time_t idle, atime; int userpos = 0; /* position of user found, 0 => not found */ snprintf(prname, sizeof(prname), "/proc/%d", utmpp->ut_pid); /* append /proc/ to proclist */ snprintf(dev, sizeof(dev), "/dev/%s", utmpp->ut_line); /* append /dev/ to base name */ msg = ""; /*.. Get information about the current process. .............................*/ if (stat(prname, &status)) msg = "Dead process: "; if (utmpp->ut_type != USER_PROCESS) msg = "Non-user process:"; if (strlen(msg)) { if (listall) printf("%s N:%-8s P:%5d Login:%s", msg, utmpp->ut_user, utmpp->ut_pid, ctime(&utmpp->ut_time)); return 0; } if (dev[5] != ':' && stat(dev, &status)) { /* if can't get status for port */ snprintf(tmp_str, 79, "Can't get status of user's terminal: %s", dev); bailout(tmp_str, 1); return 0; } /*.. Find out everything about current time, sleep time and session time. ...*/ if (utmpp->ut_time > status.st_atime) /* get last access time */ atime = utmpp->ut_time; /* proc - starttime */ else atime = status.st_atime; /* proc - accesstime */ idle = (pres_time - atime) / 60; /* total idle minutes */ /*.. Find out username and groupname of this login. .........................*/ strncpy(name, utmpp->ut_user, UT_NAMESIZE); /* get user name */ name[UT_NAMESIZE] = '\0'; /* null terminate user name string */ if (listall) printf("Checking: %-11s on %-12s I:%4ld T:%d Login: %s", name,dev, idle, utmpp->ut_type, ctime(&utmpp->ut_time)); strncpy(userlst[0].Name, name, UT_NAMESIZE); userlst[0].Name[UT_NAMESIZE] = '\0'; strncpy(userlst[0].Device, utmpp->ut_line, UT_LINESIZE); userlst[0].Device[UT_LINESIZE] = '\0'; userlst[0].IdleTime = idle; /*.. Get Position of user in userlst. .......................................*/ userpos = userfill; while ( strncmp(userlst[userpos].Name, name, UT_NAMESIZE) ) userpos--; /*.. if not found -> add user to userlst. ...................................*/ if ( userpos == 0 ) { userfill++; if (userfill > usermax) { usermax = 2 * usermax; userlst = (userdata *)realloc(userlst, sizeof(userdata) * (1 + usermax)); } strncpy(userlst[userfill].Name, name, UT_NAMESIZE); userlst[userfill].Name[UT_NAMESIZE] = '\0'; strncpy(userlst[userfill].Device, utmpp->ut_line, UT_LINESIZE); userlst[userfill].Device[UT_LINESIZE] = '\0'; userlst[userfill].IdleTime = idle; userlst[userfill].UserID = status.st_uid; userlst[userfill].SessStrt = utmpp->ut_time; userlst[userfill].WarnEnds = 0; } else { if (userlst[userpos].IdleTime > idle) { /* less idle-time found. ....*/ userlst[userpos].IdleTime = idle; strncpy(userlst[userpos].Device, utmpp->ut_line, UT_LINESIZE); userlst[userpos].Device[UT_LINESIZE] = '\0'; } if (userlst[userpos].SessStrt > utmpp->ut_time) { /* earlier start. */ userlst[userpos].SessStrt = utmpp->ut_time; } } } static int show_results() { int userpos = 0; /* position of user found, 0 => not found */ printf("\nfound: %2d\n\n", userfill); printf(" Username UserID Terminal idle Starttime BanningEnd WarningEnd\n"); for (userpos = 1; userpos<=userfill; userpos++) { printf(" --> %-10s %4d %-10s %5d %10d %10d %10d\n", userlst[userpos].Name, userlst[userpos].UserID, userlst[userpos].Device, userlst[userpos].IdleTime,userlst[userpos].SessStrt, userlst[userpos].Ban_Ends,userlst[userpos].WarnEnds); } } static int save_users() { int userpos = 0; /* position of user found, 0 => not found */ FILE* f; if (!(f = fopen(datfname, "w+"))) { bailout("Can't create data-file.", 6); return 0; } fprintf(f, "%d\n", userfill); for (userpos = 1; userpos <= userfill; userpos++) { fprintf(f, " %-10s %4d %-10s %5d %10d %10d %10d\n", userlst[userpos].Name, userlst[userpos].UserID, userlst[userpos].Device, userlst[userpos].IdleTime, userlst[userpos].SessStrt, userlst[userpos].Ban_Ends, userlst[userpos].WarnEnds); } fclose(f); } static int load_users() { int userpos = 0; /* position of user found, 0 => not found */ FILE* f; /*.. if no table exists, no problem, just return. ...........................*/ if (!(f = fopen(datfname, "r"))) return 0; /*.. check, how many lines with data will follow. ...........................*/ fscanf(f, "%d", &userfill); /*.. if necessary extend list. ..............................................*/ if (userfill > usermax) { usermax = 2 * userfill; userlst = (userdata *)realloc(userlst, sizeof(userdata) * (1 + usermax)); } /*.. read all the data-lines. ...............................................*/ for (userpos = 1; userpos <= userfill; userpos++) { fscanf(f, " %s %d %s %d %d %d %d", userlst[userpos].Name, &userlst[userpos].UserID, userlst[userpos].Device, &userlst[userpos].IdleTime, &userlst[userpos].SessStrt, &userlst[userpos].Ban_Ends, &userlst[userpos].WarnEnds); } fclose(f); } /*---------------------------------------------------------------------------*/ /*=== The following functions cope with the config-file. ===*/ /*---------------------------------------------------------------------------*/ static int set_defs(int i) { c_arr[i].name = anystrg; c_arr[i].group = anystrg; c_arr[i].line = anystrg; c_arr[i].idle = g_idle; c_arr[i].ban = 0; c_arr[i].grace = g_grace; c_arr[i].hard = g_hard; c_arr[i].mail = g_mail; c_arr[i].clear = g_clear; c_arr[i].warn = g_warn; c_arr[i].log = g_log; } static int eat_confile() { FILE *f; char *s, iline[LINELEN]; int i, lev; int idle; if (!(f=fopen(confname, "r")) ) { if (debug) printf("Can't find file: %s\n", confname); } else { while (fgets(iline, LINELEN, f)) { if (*iline == '#' || strlen(iline) <= 1) continue; /*.. check for ps=command in config-file, extract command. ...............*/ s = strstr(iline, "ps="); if (s) { ps_cmd = strcpy((char *)malloc(strlen(s) + 1), s + 3); continue; } s = strstr(iline, "nolostkill"); if (s) { lostkill = 0; continue; } set_defs(c_idx); s = strtok(iline, delims); do { lev = 1; if (!strncmp(s, "name=", 5) && *(s += 5)) c_arr[c_idx].name = strcpy((char *)malloc(strlen(s) + 1), s); else if (!strncmp(s, "group=", 6) && *(s += 6)) c_arr[c_idx].group = strcpy((char *)malloc(strlen(s) + 1), s); else if (!strncmp(s, "line=", 5) && *(s += 5)) c_arr[c_idx].line = strcpy((char *)malloc(strlen(s) + 1), s); else if (!strncmp(s, "idle=", 5) && *(s += 5)) c_arr[c_idx].idle = atoi(s); else if (!strncmp(s, "grace=", 6) && *(s += 6)) c_arr[c_idx].grace = atoi(s); else if (!strncmp(s, "ban=", 4) && *(s += 4)) c_arr[c_idx].ban =atoi(s); else { if (!strncmp(s, "no", 2)) { lev = 0; s += 2; } if (!strcmp(s, "hard")) c_arr[c_idx].hard = lev; else if (!strcmp(s, "clear")) c_arr[c_idx].clear = lev; else if (!strcmp(s, "mail")) c_arr[c_idx].mail = lev; else if (!strcmp(s, "warn")) c_arr[c_idx].warn = lev; else if (!strcmp(s, "log")) c_arr[c_idx].log = lev; else if (debug) printf("Unknown token in file: %s: %s\n", confname, s); } } while (s = strtok(0, delims)); idle = c_arr[c_idx].idle; /*.. Maybe it is necessary to reduce the max. sleeptime to shortest session. */ if (0 < idle) /* but not to zero seconds. */ if (60 * idle < sleep_max) sleep_max = 60 * idle; c_idx++; } fclose(f); } if (!c_idx) /* if no entries made yet */ set_defs(c_idx++); /* make one */ if (debug) { printf("\nConfig File:\n"); printf("name group line idle grace mail warn log hard ban\n"); printf("----------------------------------------------------------\n"); for(i = 0; i < c_idx; i++) printf("%-8s %-8s %-6s %3d %5d %4d %4d %3d %4d %4d\n", c_arr[i].name, c_arr[i].group, c_arr[i].line, c_arr[i].idle, c_arr[i].grace, c_arr[i].mail, c_arr[i].warn, c_arr[i].log, c_arr[i].hard, c_arr[i].ban); printf("\n"); printf("[%s]\n", ps_cmd); if (lostkill) printf("Lost processes will be killed.\n"); else printf("Lost processes stay alive.\n"); } } /* I've apparently found some bug in certain LINUX versions of the */ /* regular expressions library routines. One of these following two */ /* versions of the routine should work for you. */ /* #define AVOID_REGEX_BUG*/ #ifdef AVOID_REGEX_BUG /* some strange bug in re_exec */ static int pat_match(char *pattern, char *strg) { struct re_pattern_buffer rpb; int len, retval = 0; /*if (debug) printf("pat_match:%s:%s:\n", pattern, strg);*/ len = strlen(pattern + 256); rpb.buffer = malloc(len); rpb.allocated = len; rpb.fastmap = 0; rpb.translate = 0; if (!re_compile_pattern(pattern, strlen(pattern), &rpb)) { if (re_match(&rpb, strg, strlen(strg), 0, 0) == strlen(strg)) retval = 1; } free(rpb.buffer); return retval; } #else /* return true if strg matches the regex in pattern */ static int pat_match(char *pattern, char *strg) { re_comp(pattern); return re_exec(strg); } #endif /*---------------------------------------------------------------------------*/ /*=== This function checks whether we have to kill a session. ===*/ /*---------------------------------------------------------------------------*/ static int check_idle(userdata *akt_usr) { char ddev[STRLEN], *gn = ".*"; char dev[STRLEN], name[STRLEN], prname[STRLEN]; int idle; struct stat status; time_t start, stime; struct passwd *passwd_entry; struct group *group_entry; conf_el *ce; int i; strncpy(name, akt_usr->Name, UT_NAMESIZE); strncpy(dev, akt_usr->Device, UT_LINESIZE); idle = akt_usr->IdleTime; stime = pres_time - akt_usr->SessStrt; akt_usr->IdleTime = 30000; /* 20 days will "clear" the idletime */ if (debug) printf("\nuser: %-10s %-10s %-d\n", name, dev, idle); if(dev[0] == ':') /* ignore xdm */ return 0; snprintf(ddev, sizeof(ddev), "/dev/%s", dev); /* append /dev/ to base name */ /*.. If user has logged out, check his Session time and so. .................*/ if (debug) printf("now: %ld = %s", pres_time, ctime(&pres_time)); if (listall) printf("\nChecking: %-11s on %-12s I:%-4d\n", name, dev, idle); /* now try to find the group of this person */ /* if usernames in utmp are limited to 8 chars, we will may fail on */ /* names that are longer than this, so we'll try to find it by uid */ if (!(passwd_entry = getpwnam(name))) /* If can't find by name */ passwd_entry = getpwuid(akt_usr->UserID); /* try by uid */ if (passwd_entry) { strncpy(name, passwd_entry->pw_name, STRLEN); if (group_entry = getgrgid(passwd_entry->pw_gid)) gn = group_entry->gr_name; else if (debug) printf("Can't find group entry for user: %s\n", name); } else if (debug) { printf("Can't find password entry for user: %s\n", name); } for(i = 0; i < c_idx; i++) { if (pat_match(c_arr[i].name, name) && pat_match(c_arr[i].group, gn) && pat_match(c_arr[i].line, dev)) { // if (debug) // printf("Match #%2d: U:%-12s Grp:%-8s Line:%-9s Pid:%-6d Sess:%3d:%02d\n", // i+1, name, gn, utmpp->ut_line, utmpp->ut_pid, stime / 60, stime % 60); if (c_arr[i].idle < 0) { /* if user exempt (idle<0) */ if (debug) printf("User exempt\n"); return 0; /* then don't kill him */ } ce = &c_arr[i]; /* get address of matched record */ break; } } if (i >= c_idx) { if (debug) printf("No match for process\n"); return 0; } /* device empty or new user => check whether banning is over. ...............*/ if (stat(ddev, &status) || status.st_uid != akt_usr->UserID) { if (pres_time>akt_usr->Ban_Ends) { /* End of banning-time */ akt_usr->SessStrt = pres_time; /* allow new session. */ akt_usr->Ban_Ends = 0; /* (just for debugging). */ akt_usr->WarnEnds = 0; /* user may return, now. */ return 2; /* 0 => user done. */ } else { lower_sleep(ChckSleep); /* user might come back */ } strncpy(akt_usr->Device, ".", UT_LINESIZE); /* "Flag": user logged out. */ if (debug) { if (stat(ddev, &status)) { printf("user has logged out.\n"); } else if (status.st_uid != akt_usr->UserID) { printf("%4d <> %4d\n", status.st_uid, akt_usr->UserID); printf("user has changed -> do not disturb.\n"); } } return 0; } /* Check whether to knock out this user. ....................................*/ if (!c_arr[i].hard) { /* if considering idle time */ if (akt_usr->Ban_Ends < pres_time) { if (idle < ce->idle) { /* if user was recently active */ akt_usr->WarnEnds = 0; /* set to not warned. */ return 0; } if (debug) printf("Subject to logout Idle time: %4d (%2d allowed)\n", idle,ce->idle); } else if (debug) { printf("User temporary banned.\n"); } } else { int time_left; /*.. In case, he leaves now, his ban will end after his banning-time. .......*/ /*.. This will also increase his banning-time in case he returnes to early. .*/ /*.. Set end of banning to current time + time to ban user. ................*/ akt_usr->Ban_Ends = pres_time + 60 * ce->ban; if (debug) printf("Banning should end: %10d\n", akt_usr->Ban_Ends); /*.. Make sure, daemon doesn't sleep too long from now. .....................*/ if (debug) printf("idle-state: %3d / %d:\n", idle, ce->idle); if (debug) printf("sess-state: %3ld / %d:\n", stime / 60, ce->idle); time_left = 60 * ce->idle - stime; if (debug) printf("time left: %4d sec.\n", time_left); if (0 < time_left) { /* there is some time left */ lower_sleep(time_left); return 0; } else { lower_sleep(ce->grace); /* process is to be killed */ } if (debug) printf("Subject to logout Total time: %4ld (%2d allowed)\n", stime / 60, ce->idle); } if (stat(ddev, &status)) { bailout("Can't get status of user's terminal", 2); return 0; } /*.. action either warning or killing. */ // if (akt_usr->WarnEndsed && (pres_time > akt_usr->Ban_Ends) ) { if (0 < akt_usr->WarnEnds && (pres_time > akt_usr->WarnEnds) ) { if (debug) printf("Killing user, now.\n"); if (kill_PIDs(name, dev) == 1) /* try to kill users' processes */ mesg(LOGOFF, name, ddev, stime / 60, idle, ce); /* mail to user */ else mesg(NOLOGOFF, name, ddev, stime / 60, idle, ce); /* couldn't kill */ if (ce->hard) { akt_usr->WarnEnds =-1; /* if user returnes at ones -> angry */ } else { akt_usr->WarnEnds =-2; akt_usr->Ban_Ends = pres_time /* give other users a chance */ + Idle_Ban; /* to catch this computer. */ lower_sleep(ChckSleep); } } else if (akt_usr->WarnEnds == -2) { /* punish being idle for too long. */ mesg(IDLEPUNISH, name, ddev, stime / 60, idle, ce); akt_usr->WarnEnds = pres_time + 5; /* give some time to read message */ lower_sleep(5); if (debug) printf("idle-punish\n"); } else if (akt_usr->WarnEnds==-1) { mesg(ANGRY, name, ddev, stime / 60, idle, ce); /* angry about user. */ if (debug) printf("I am angry, user returned...\n"); if (kill_PIDs(name, dev) == 1) /* try to kill user, at once */ mesg(LOGOFF, name, ddev, stime / 60, idle, ce); /* mail to user */ else mesg(NOLOGOFF, name, ddev, stime / 60, idle, ce); /* couldn't kill */ } else { if (akt_usr->WarnEnds == 0) { mesg(WARNING, name, ddev, stime / 60, idle, ce); /* try to warn user. */ akt_usr->WarnEnds = pres_time + ce->grace; /* wait until grace ends */ if (debug) printf("Warning user:%s Line:%s Sleep %d sec\n", name, dev, ce->grace); } lower_sleep(ce->grace); } return 0; } /*---------------------------------------------------------------------------*/ /*=== This function finds out the PIDs of the current user. ===*/ /*---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ static void get_PIDs(char *u_name, char *u_dev) /* find processes of a given user. */ /*----------------------------------------------------------------------------*/ /* this version assumes that ps -au returns one header-line and then */ /* lines with usernames, pids and some other stuff */ { char prname[LINELEN], iline[LINELEN]; char *s; char *ps_name, *ps_pid, *ps_dev; struct stat status; FILE *ps; int i; pid_t pid; uid_t uid; if (!(ps = popen(ps_cmd, "r")) ) { bailout("Can't use ps program", 6); return; } fgets(iline, LINELEN, ps); /* get header-line */ ids_fill = 0; while (fgets(iline, LINELEN, ps)) { ps_name = strtok(iline, delims); /* manual: Never use this function. */ ps_pid = strtok(0, delims); pid = atoi(ps_pid); // TODO: this is not flexible about the terminal position in the ps output // for(i = 0; i < 5; i++) ps_dev = strtok(0, delims); snprintf(prname, sizeof(prname), "/proc/%d", pid); /* append /proc/ to proclist */ if (stat(prname, &status)) printf("Dead process: \n"); uid = status.st_uid; if (debug) printf("%-8s/%s -> %5s %5d %5d\n", ps_name, ps_dev, ps_pid, pid, uid); if ( strcmp(u_name, ps_name) == 0 && strcmp(u_dev, ps_dev) == 0 ) { if (debug) printf(" -> ok, Name = %s, dev = %s => kill.\n", u_name, u_dev); ids_fill++; if (ids_fill > ids_max) { ids_max = 2 * (ids_max); ids_lst = (int *)realloc(ids_lst, sizeof(int) * (1 + (ids_max))); } ids_lst[ids_fill] = pid; } } fclose(ps); if (debug) { printf (" |-> "); for (i = 1; i <= ids_fill; i++) printf (" %5d", ids_lst[i]); printf ("\n"); } } /*---------------------------------------------------------------------------*/ /*=== The following functions have a murder job. ===*/ /*---------------------------------------------------------------------------*/ static int kill_PIDs(char *u_name, char *u_dev) { int i, ok = 1; ids_max = 50; ids_lst = (int *)calloc(sizeof(int), 1 + (int)(ids_max)); if (debug) printf("\nget PIDs for %s\n", u_name); /*.. Tell processes to hang up. .............................................*/ // ids_fill = 0; get_PIDs(u_name, u_dev); if (do_bite) for (i = 1; i <= ids_fill; i++) kill_HUP(ids_lst[i]); sleep(HUP_WAIT); /*.. Check for processes that still survived and now kill them. .............*/ /*.. This will also kill a user that returns at once. Without warning. :) ...*/ ids_fill = 0; get_PIDs(u_name, u_dev); if (do_bite) for (i = 1; i <= ids_fill; i++) kill_KILL(ids_lst[i]); sleep(KILLWAIT); /*.. Check for processes that survived killing. .............................*/ if (do_bite) for (i = 1; i <= ids_fill; i++) { if (kill_Res(ids_lst[i])) ok = 0; } free(ids_lst); return ok; } /* terminate process using SIGHUP, first. */ static int kill_HUP(int pid) { kill(pid, SIGHUP); /* first send "hangup" signal */ } /* terminate process using SIGKILL, later.*/ static int kill_KILL(int pid) { kill(pid, SIGKILL); /* then send sure "kill" signal. */ } /* Check for processes that refused to die.*/ static int kill_Res(int pid) { if (!kill(pid, 0)) return 1; /* failure--refuses to die! */ else return 0; /* successful kill with SIGKILL */ } /*---------------------------------------------------------------------------*/ /*=== The following functions spread the messages to everywhere. ===*/ /*---------------------------------------------------------------------------*/ static int mesg(int flag, char *name, char *dev, int stime, int idle, conf_el *ce) { char mbuf[LINELEN]; /* message buffer */ char *hint; time_t tvec; FILE *fp, *mprog; time(&tvec); /* tvec = current time. .....*/ if (flag == IDLEPUNISH && ce->warn) { /* process warning message. */ hint = "** IDLE-PUNISH **"; if (!(fp = fopen(dev, "w")) ) { bailout("Can't open user's terminal", 5); return 0; } if (ce->clear) { snprintf(mbuf, sizeof(mbuf), "clear >%s", dev); system (mbuf); } fprintf(fp, "\n\n\r"); /* \r is sometimes needed...*/ fprintf(fp, ".--------------------------------------------.\n\r"); fprintf(fp, "| %10s, you have been idle too long. |\n\r", name); fprintf(fp, "| Punishment: Log out for %3d seconds! |\n\r", Idle_Ban); fprintf(fp, "`--------------------------------------------'\n\r"); fprintf(fp, "\07\n"); sleep(1); fprintf(fp, "\07\n"); sleep(1); fprintf(fp, "\07\n\r"); sleep(10); /* just some time to read this message */ fclose(fp); } if (flag == ANGRY && ce->warn) { /* process warning message. */ hint = " ** ANGRY **"; if (!(fp = fopen(dev, "w")) ) { bailout("Can't open user's terminal", 5); return 0; } if (ce->clear) { snprintf(mbuf, sizeof(mbuf), "clear >%s", dev); system (mbuf); } if (ce->hard) { fprintf(fp, "\n\n\r"); /* \r is sometimes needed...*/ fprintf(fp, ".--------------------------------------------------.\n\r"); fprintf(fp, "| %10s, you have just been kicked off. |\n\r", name); fprintf(fp, "| Make off, don't try it again, today. |\n\r"); fprintf(fp, "`--------------------------------------------------'\n\r"); fprintf(fp, "\07\n"); sleep(1); fprintf(fp, "\07\n"); sleep(1); fprintf(fp, "\07\n\r"); sleep(10); /* just some time to read this message */ } fclose(fp); } if (flag == WARNING && ce->warn) { /* process warning message. */ hint = "** NOTIFIED **"; if (!(fp = fopen(dev, "w")) ) { bailout("Can't open user's terminal", 5); return 0; } if (ce->clear) { snprintf(mbuf, sizeof(mbuf), "clear >%s", dev); system(mbuf); } if (ce->hard) { fprintf(fp, "\n\n\r"); /* \r is sometimes needed...*/ fprintf(fp, ".--------------------------------------------------.\n\r"); fprintf(fp, "| %10s: You've been on for %3d min. |\n\r", name, stime); fprintf(fp, "| You'll be logged off in %3d sec. so finish up. |\n\r", ce->grace); fprintf(fp, "`--------------------------------------------------'\n\r"); fprintf(fp, "\07\n"); sleep(1); fprintf(fp, "\07\n"); sleep(1); fprintf(fp, "\07\n\r"); } else { fprintf(fp, "\n\n\r"); /* \r is sometimes needed...*/ fprintf(fp, ".----------------------------------------------.\n\r"); fprintf(fp, "| %10s: You've been idle for %3d min. |\n\r", name, idle); fprintf(fp, "| You'll be logged off in %3d sec |\n\r", ce->grace); fprintf(fp, "| unless you hit a key. |\n\r"); fprintf(fp, "`----------------------------------------------'\n\r"); /*.. Try to wake up sleeping user by beeping 3 times. . .....................*/ fprintf(fp, "\07\n"); sleep(1); fprintf(fp, "\07\n"); sleep(1); fprintf(fp, "\07\n\r"); } fclose(fp); if (ce->mail) { snprintf(mbuf, sizeof(mbuf), "/usr/bin/mail -s \"++WARNING - LOG-OFF ++\" %s", name); /* open pipe to mail program for writing */ if (!(mprog = popen(mbuf, "w")) ) { bailout("Can't use /usr/bin/mail program", 6); return 0; } if (ce->hard) { fprintf(mprog, "Your session-limit will be reached soon.\n"); fprintf(mprog, " %s: You've been on for %3d min.\n", name, stime); fprintf(mprog, " You'll be logged off in %3d sec.\n", ce->grace); fprintf(mprog, " So finish up, please.\n"); } else { fprintf(mprog, "You have been idle for quite a long time.\n"); fprintf(mprog, " %s: You've been idle for %3d min.\n", name, stime); fprintf(mprog, " You'll be logged off in %3d sec.\n", ce->grace); fprintf(mprog, " Please: Type something into a terminal \n"); fprintf(mprog, " or you'll be kicked off.\n"); } fclose(mprog); } } if (flag == LOGOFF) { hint = "** LOGOFF **"; if (ce->mail) { snprintf(mbuf, sizeof(mbuf), "/usr/bin/mail -s \"Logged off, you were idle\" %s", name); /* open pipe to mail program for writing */ if (!(mprog = popen(mbuf, "w")) ) { bailout("Can't use /usr/bin/mail program", 6); return 0; } fprintf(mprog, "Subject: Excess Idle Time\n\n"); fprintf(mprog, " Logged off - %s - %s\n", name, ctime(&tvec)); fprintf(mprog, " - excess idle time - \n"); fprintf(mprog, " on tty = %s\n",dev+5); fclose(mprog); } } if (flag == NOLOGOFF) { hint = "** LOGOFF FAILED **"; if (ce->mail) { snprintf(mbuf, sizeof(mbuf), "/usr/bin/mail -s \"Couldn't log out [%s] \" root", name); if ((mprog = popen(mbuf, "w")) == (FILE *)NULL) { bailout("Can't use /usr/bin/mail program", 7); return 0; } fprintf(mprog, "Subject: Can't logoff %s\n", name); fprintf(mprog, "Can't Log off - %s %s\n", name, ctime(&tvec)); fprintf(mprog, "tty = %s\n", dev + 5); fclose(mprog); } } if (ce->log) { /* Generate logfile message */ char msg[100]; snprintf(msg, sizeof(msg), "%-20s %-8s %-5s idle:%3d sess:%3d", hint, name, dev + 5, idle, stime); log_msg(msg); } return 0; } /* This function adds something to a logfile. ......*/ static int log_msg(char *message) { FILE *log = 0; struct stat status; char str_time[30]; if (stat(logfname, &status) >= 0) { /* if logfile exists */ log = fopen(logfname, "a"); /* open to append */ if (log == NULL) return 1; /* fopen failed. */ snprintf(str_time, sizeof(str_time), "%s", ctime(&pres_time) + 3); str_time[strlen(str_time) - 1] = 0; fprintf(log, "%s - %s\n", str_time, message); fclose(log); return 0; } } /* Handle error message. */ static int bailout(char *message, int status) { char msg[100]; /* Try to log the message. */ snprintf(msg, sizeof(msg), "** ERROR ** %s", message); log_msg(msg); } /*.. reduce time to sleep for the next time the daemon falls asleep. ........*/ static int lower_sleep(int sleep_left) { if (0 < sleep_left && sleep_left < sleeptime) sleeptime = sleep_left; } /*---------------------------------------------------------------------------*/ /*=== By the way have a look for forgotten user-processes ===*/ /*---------------------------------------------------------------------------*/ static int kill_lost_PIDs() { char prname[LINELEN], iline[LINELEN]; char *s; char *ps_name, *ps_pid; struct stat status; FILE *ps; int i; pid_t pid; uid_t uid; char mbuf[LINELEN]; /* message buffer */ int userpos = 0; /* position of user found, 0 => not found */ /*.. have ps tell us all current users, uids and pids. ......................*/ if (!(ps = popen(ps_cmd, "r")) ) { bailout("Can't use ps program", 6); return 0; } fgets(iline, LINELEN, ps); /* get header-line */ ids_fill = 0; while (fgets(iline, LINELEN, ps)) { ps_name = strtok(iline, delims); /* manual: Never use this function. */ ps_pid = strtok(0, delims); pid = atoi(ps_pid); snprintf(prname, sizeof(prname), "/proc/%d", pid); /* append /proc/ to proclist */ if (stat(prname, &status)) { userpos = -1; /* => process will be killed. */ if (do_bite) kill(pid, SIGKILL); /* send the "kill" signal */ snprintf(mbuf, sizeof(mbuf), "Dead , killed: %-10s %5d : %5d", ps_name, uid, pid); log_msg(mbuf); } else { uid = status.st_uid; if (debug) printf("%-8s -> %5s %5d %5d\n", ps_name, ps_pid, pid, uid); if (1000 <= uid && uid != 65534) { /* neither system accounts nor nobody */ /*.. Get Position of user in userlst. .......................................*/ strncpy(userlst[0].Name, ps_name, UT_NAMESIZE); userlst[0].Name[UT_NAMESIZE] = '\0'; userpos = userfill; while ( strncmp(userlst[userpos].Name, ps_name, UT_NAMESIZE) ) userpos--; if (userpos == 0 ) { /* user not found => not active */ if (do_bite) kill(pid, SIGKILL); /* send the "kill" signal */ snprintf(mbuf, sizeof(mbuf), "Lost, killed: %-10s %5d : %5d", ps_name, uid, pid); log_msg(mbuf); } else if(strlen(userlst[userpos].Device) == 1) { /* "." */ if (do_bite) kill(pid, SIGKILL); /* send the "kill" signal */ snprintf(mbuf, sizeof(mbuf), "Left, killed: %-10s %5d : %5d", ps_name, uid, pid); log_msg(mbuf); } } } /* Read to the end of line to avoid parsing the rest of the command * line in next round and getting a segfault as ps_pid will be null!! */ i = strlen(iline); while (iline[i-1] != '\n') { if (!fgets(iline, LINELEN, ps)) { /* end of file, exit*/ fclose(ps); return 0; } i = strlen(iline); } } fclose(ps); } autolog-0.42/autolog.conf000066400000000000000000000031541401275074600154430ustar00rootroot00000000000000# Enter a regular expression for the username, group and tty line. # All three expressions must be matched before the rest of the line will # be applied to any process. # If the process has been idle (or connected) more than "idle" minutes, # autolog will attempt to kill the process. # If idle<0, the process is exempt. # If idle=0, the users must not be idle for to long :) -> debugging # If "nowarn" is asserted, the user will # not be warned that it is about to be killed. # After "grace" seconds, autolog will attempt to kill the process. # If "mail" is asserted, mail will be sent to the user # telling how his process met its end. # If "hard is asserted, the process will be killed # after "idle" minutes of total session time (rather than idle time). # ban=xx: A user extending his session-limit will be banned for xx minutes. name=ppp-.* idle=-1 line=ttyS2 line=pty.* idle=30 grace=30 nomail nolog group=games idle=10 grace=60 group=lynx.* idle=10 grace=60 clear # protected users name=root idle=-1 # idle - limits group=student idle=15 grace=180 # session - limits group=users idle=60 grace=120 hard ban=20 clear name=guest idle=60 grace=60 hard ban=5 clear # This makes it possible to change the options... # make sure, ps with its options returns one heading-line # and lines beginning with: USERNAME PID # e.g.: cj 2568 # or : cj 2568 0.0 0.0 1944 0 pts/2 ..... [telnet] # No spaces or tabs before this option, please. # ps=ps -ef # ps=ps aux # ps=ps ax o user o pid # To stop autolog from killing lost processes, umcomment the next line. nolostkillautolog-0.42/autolog.conf.5000066400000000000000000000100521401275074600156010ustar00rootroot00000000000000.TH autolog.conf 5 "Configuration Files" "Linux" \" -*- nroff -*- .SH NAME autolog.conf \- Configuration file for the autolog command .SH DESCRIPTION The configuration file consists of multiple lines, each of which describes a class of processes subject (or not subject) to a certain auto logout procedure. A line consists of any number of switches. Value switches are of the form: "name=value". Boolean switches are of the form: "name" or "noname". .PP Using these switches, you can define a username, a group, and a tty line. These descriptions can contain wildcard characters (regular expressions). You can also define an idle time, a grace period and a few other options. When reading the configuration file, the program creates a record for each configuration line. A value is assigned to each variable in the record regardless of whether or not you specify one explicitly. Values for missing variables are provided by defaults which are compiled in and can be modified from the command line. .PP If no entries are found matching a given process, that process will be spared from an untimely demise. Therefore, it is a good idea to always have a "cleanup" line at the end of the configuration file to catch anything that might have been missed by the more explicit definitions. Since the default name, group, and line are all ".+", a simple line like: idle=30 will do. Actually, any one switch can be specified on the line and all the others will get the default values. .PP If no configuration file is found, the program will create a single entry which has all values set from the defaults. This entry will match any process on any port (name=.+ line=.+ group=.+). Therefore, the default action is to kill all processes. .SH ENTRIES .TP .B name= A regular expression specifying which username(s) to match. .TP .B group= A regular expression specifying which group(s) to match. .TP .B line= A regular expression specifying which tty line(s) to match. Omit the "/dev/" part of the special name. .TP .B idle= An integer specifying the number of \-\-minutes\-\- of idle (or connect) time to allow before beginning automatic logoff. An idle time of 0 exempts the process from automatic logoff. .TP .B grace= An integer specifying the number of \-\-seconds\-\- from the initial warning to killing the process. .TP .B ban= An integer specifying the number of \-\-minutes\-\- from killing the process to the moment, the user may login again. (after exceeding his session). .TP .B hard A boolean value indicating total connect time will be considered rather than idle time. .TP .B mail A boolean value indicating that mail will be sent to the user explaining that he was killed. .TP .B clear A boolean value indicating that the screen will be cleared before a warning message is sent. .TP .B warn A boolean value indicating that a warning message will be sent at the beginning of the "grace" period. .TP .B log A boolean value indicating that activities will be logged to the logfile (if it exists). .SH FURTHER ENTRIES .PP There is another group of entries, which allows one to set some general options. Each of them takes a whole line. Don't mix them with the other entries from before. .TP .B nolostkill A boolean value indicating whether lost processes should be killed. If there is a process with uid between 500 and 60000 and the owner is not logged in, it is assumed as lost and will be killed. .TP .B ps=command on some strange or old systems the ps-command has different parameters. This makes it possible to set a completely different command. It is only important, that this command delivers one heading line and then lines with usernames and process-ids (pid). e.g.: ps=ps aux .SH EXAMPLE name=root line=tty[1-7] idle=0 name=guest idle=5 grace=60 nomail hard warn group=lynx-.* idle=10 grace=60 clear idle=60 grace=30 .SH AUTHOR Kyle Bateman (autolog 0.35), .PD 0 .TP James Dingwall .TP (autolog 0.41) .PD .PP This manual page was modified for \fBDebian\fP by Paul Telford autolog-0.42/autolog.conf.debug000066400000000000000000000033421401275074600165270ustar00rootroot00000000000000# # This is the config-file, I (CJ) do use for debugging. # ==================================================== # # Enter a regular expression for the username, group and tty line. # All three expressions must be matched before the rest of the line will # be applied to any process. # If the process has been idle (or connected) more than "idle" minutes, # autolog will attempt to kill the process. # If idle<0, the process is exempt. # If idle=0, the users must not be idle for to long :) -> debugging # If "nowarn" is asserted, the user will # not be warned that it is about to be killed. # After "grace" seconds, autolog will attempt to kill the process. # If "mail" is asserted, mail will be sent to the user # telling how his process met its end. # If "hard is asserted, the process will be killed # after "idle" minutes of total session time (rather than idle time). # ban=xx: A user extending his session-limit will be banned for xx minutes. name=ppp-.* idle=-1 line=ttyS2 line=pty.* idle=30 grace=30 nomail nolog group=games idle=10 grace=60 group=lynx.* idle=10 grace=60 clear # protected users name=root idle=-1 # idle - limits group=student idle=15 grace=180 # session - limits group=users idle=0 grace=02 hard ban=1 clear name=guest idle=60 grace=60 hard ban=5 clear # This makes it possible to change the options... # make sure, ps with its options returns one heading-line # and lines beginning with: USERNAME PID # e.g.: cj 2568 # or : cj 2568 0.0 0.0 1944 0 pts/2 ..... [telnet] # No spaces or tabs before this option, please. # ps=ps -ef # ps=ps -aux # ps=ps ax o user o pid # To stop autolog from killing lost processes, umcomment the next line. # nolostkill autolog-0.42/autolog.dump000066400000000000000000000060241401275074600154620ustar00rootroot00000000000000/*****************************************************************************/ /* */ /* Programm: autolog.dump C-Programm to log out sleeping users */ /* */ /* Autor: Carsten Juerges Erster Versuch: 06.04.2000 */ /* Kurze Wanne 1 Letztes Update: 10.04.2000 */ /* 30926 Seelze */ /* juerges@cip-bau.uni-hannover.de */ /* */ /* Rechner: AMD K6-2 SuSE Linux 6.3 */ /* */ /* Meldung: This version seems to worke quite good. */ /* */ /* This files stores the old functions which have been rewritten. */ /* */ /*****************************************************************************/ /*===========================================================================*/ /* get_PIDs ===*/ /* - found, that some (old) ps-versions do not support my options ===*/ /*---------------------------------------------------------------------------*/ get_PIDs(char *u_name){ char mbuf[LINELEN]; /* message buffer */ FILE *ps; int i; int pid; sprintf(mbuf, "ps -U %s --no-heading o pid",u_name); //## if (!(ps = popen(mbuf, "r")) ) bailout("Can't use ps program", 6); while (!feof(ps)) { pid=0; fscanf(ps,"%d", &pid); //## if (pid>1){ /* otherwise feof or pid=0. can't kill pid=1 anyway. */ ids_fill++; if (ids_fill > ids_max) { ids_max = 2*(ids_max); ids_lst = (int*) realloc(ids_lst,sizeof(int)* (1+(ids_max))); } ids_lst[ids_fill]=pid; } } fclose(ps); if (debug) { printf (" |-> "); for (i=1; i<=ids_fill; i++) printf (" %5d",ids_lst[i]); printf ("\n"); } } /*---------------------------------------------------------------------------*/ kill_lost_PIDs(){ char mbuf[LINELEN]; /* message buffer */ FILE *ps; char u_name[20]; int pid, uid; int userpos=0; /* position of user found, 0 => not found */ /*.. have ps tell us all current users, uids and pids. ......................*/ sprintf(mbuf, "ps ax --no-heading o user o uid o pid"); //## if (debug) printf("\n"); if (!(ps = popen(mbuf, "r")) ) bailout("Can't use ps program", 6); while (!feof(ps)) { pid=0; fscanf(ps,"%s", u_name); //## fscanf(ps,"%d", &uid); //## fscanf(ps,"%d", &pid); //## if (pid>1){ /* otherwise feof or pid=0. can't kill pid=1 anyway. */ if (100 < uid && uid < 65534){ /* neither root nor nobody */ /*.. Get Position of user in userlst. .......................................*/ strcpy(userlst[0].Name, u_name); userpos=userfill; while ( strcmp(userlst[userpos].Name,u_name) ) userpos--; if (userpos ==0 ){ /* could not find this user => not active */ if (do_bite) kill(pid, SIGKILL); /* send the "kill" signal */ if (debug){ printf("kill: %-10s %5d : %5d\n",u_name,uid,pid); } } } } } fclose(ps); } /*===========================================================================*/ autolog-0.42/autolog.init000077500000000000000000000016261401275074600154660ustar00rootroot00000000000000#! /bin/sh # Copyright (c) 2000 Carsten Juerges, Hannover, Germany. All rights reserved. # # Author: Carsten Juerges , 2000 # # /sbin/init.d/autolog # . /etc/rc.config base=${0##*/} link=${base#*[SK][0-9][0-9]} test $link = $base && START_AUTOLOG=yes test "$START_AUTOLOG" = yes || exit 0 export PATH=/bin:/usr/bin:/sbin:/usr/sbin export HOME=/ return=$rc_done case "$1" in start) echo -n "Starting autolog daemon" startproc /usr/sbin/autolog || return=$rc_failed echo -e "$return" ;; stop) echo -n "Shutting down autolog daemon" killproc -TERM /usr/sbin/autolog || return=$rc_failed echo -e "$return" ;; restart) $0 stop && $0 start || return=$rc_failed ;; status) checkproc /usr/sbin/autolog && echo "autolog up" || echo "No autolog" ;; *) echo "Usage: $0 {start|stop|status|restart}" exit 1 esac test "$return" = "$rc_done" || exit 1 exit 0 autolog-0.42/autolog.log000066400000000000000000000000511401275074600152700ustar00rootroot00000000000000 Apr 9 19:55:29 2000 - Starting Service