2009-01-05 07:11:58 +01:00
|
|
|
/*
|
2020-10-31 10:10:54 +01:00
|
|
|
"@(#) timeoutd.c 1.6 by Shane Alderton"
|
|
|
|
based on:
|
|
|
|
"@(#) autologout.c by David Dickson"
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
Thanks to:
|
2020-10-31 10:10:54 +01:00
|
|
|
David Dickson for writing the original autologout.c
|
|
|
|
programme upon which this programme was based.
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
*/
|
2008-04-02 02:15:25 +02:00
|
|
|
/* #define DEBUG _DEBUG_ */
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/ioctl.h>
|
2009-01-05 07:11:58 +01:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
2008-04-02 02:15:25 +02:00
|
|
|
#include <sys/wait.h>
|
2009-01-05 07:11:58 +01:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <utmp.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <grp.h>
|
|
|
|
#include <sys/syslog.h>
|
|
|
|
#include <time.h>
|
2020-12-16 23:15:55 +01:00
|
|
|
#include <sys/resource.h>
|
2009-01-05 07:11:58 +01:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <termios.h>
|
|
|
|
#include <fcntl.h>
|
2008-04-02 02:15:25 +02:00
|
|
|
#include <dirent.h>
|
|
|
|
|
|
|
|
#ifdef TIMEOUTDX11
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/extensions/scrnsaver.h>
|
|
|
|
|
|
|
|
#define TIMEOUTD_XSESSION_NONE 0
|
|
|
|
#define TIMEOUTD_XSESSION_LOCAL 1
|
|
|
|
#define TIMEOUTD_XSESSION_REMOTE 2
|
|
|
|
#endif
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
#define OPENLOG_FLAGS LOG_CONS|LOG_PID
|
|
|
|
#define SYSLOG_DEBUG LOG_DEBUG
|
|
|
|
|
|
|
|
#ifndef CONFIG
|
2008-04-02 02:15:25 +02:00
|
|
|
#define CONFIG "/etc/timeouts"
|
2009-01-05 07:11:58 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#define MAXLINES 512
|
|
|
|
#define max(a,b) ((a)>(b)?(a):(b))
|
|
|
|
|
|
|
|
#define ACTIVE 1
|
|
|
|
#define IDLEMAX 2
|
|
|
|
#define SESSMAX 3
|
|
|
|
#define DAYMAX 4
|
|
|
|
#define NOLOGIN 5
|
2008-04-02 02:15:25 +02:00
|
|
|
/*#define XSESSION 6*/
|
2009-01-05 07:11:58 +01:00
|
|
|
#define IDLEMSG 0
|
|
|
|
#define SESSMSG 1
|
|
|
|
#define DAYMSG 2
|
|
|
|
#define NOLOGINMSG 3
|
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
#define KWAIT 5 /* Time to wait after sending a kill signal */
|
|
|
|
|
|
|
|
char *limit_names[] = { "idle", "session", "daily", "nologin" };
|
|
|
|
|
|
|
|
char *daynames[] = { "SU", "MO", "TU", "WE", "TH", "FR", "SA", "WK", "AL", NULL };
|
|
|
|
char daynums[] = { 1, 2, 4, 8, 16, 32, 64, 62, 127, 0 };
|
|
|
|
|
|
|
|
struct utmp *utmpp; /* pointer to utmp file entry */
|
|
|
|
char *ctime(); /* returns pointer to time string */
|
|
|
|
struct utmp *getutent(); /* returns next utmp file entry */
|
|
|
|
void shut_down();
|
|
|
|
void read_config();
|
|
|
|
void reread_config();
|
|
|
|
void reapchild();
|
|
|
|
void free_wtmp();
|
|
|
|
void check_idle();
|
|
|
|
void read_wtmp();
|
|
|
|
void bailout();
|
|
|
|
char chk_timeout();
|
|
|
|
void logoff_msg();
|
|
|
|
void killit();
|
|
|
|
int getdisc();
|
|
|
|
int chk_xsession(); /* seppy: is it a X-Session? */
|
|
|
|
void killit_xsession(); /* seppy: kill the X-Session */
|
|
|
|
int chk_ssh(pid_t pid); /* seppy: check if user is logged in via ssh (we have to
|
|
|
|
handle that different... ;( */
|
|
|
|
char *getusr(pid_t pid); /*seppy: get the owner of a running process */
|
|
|
|
void segfault(); /* seppy: catch segfault and log them */
|
|
|
|
int chk_xterm(); /* seppy: is it a xterm? */
|
|
|
|
pid_t getcpid(); /* seppy: get the child's pid. Needed for ssh */
|
2008-04-02 02:15:25 +02:00
|
|
|
|
|
|
|
#ifdef TIMEOUTDX11
|
2020-10-31 10:10:54 +01:00
|
|
|
Time get_xidle(); /* seppy: how long is user idle? (user,display) */
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
|
|
|
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
struct ut_list {
|
2020-10-31 10:10:54 +01:00
|
|
|
struct utmp elem;
|
|
|
|
struct ut_list *next;
|
2009-01-05 07:11:58 +01:00
|
|
|
};
|
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
struct ut_list *wtmplist = (struct ut_list *) NULL;
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
struct time_ent {
|
2020-10-31 10:10:54 +01:00
|
|
|
int days;
|
|
|
|
int starttime;
|
|
|
|
int endtime;
|
2009-01-05 07:11:58 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct config_ent {
|
2020-10-31 10:10:54 +01:00
|
|
|
struct time_ent *times;
|
|
|
|
char *ttys;
|
|
|
|
char *users;
|
|
|
|
char *groups;
|
|
|
|
char login_allowed;
|
|
|
|
int idlemax;
|
|
|
|
int sessmax;
|
|
|
|
int daymax;
|
|
|
|
int warntime;
|
2020-11-25 17:44:05 +01:00
|
|
|
char *messages[4];
|
2009-01-05 07:11:58 +01:00
|
|
|
};
|
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
struct config_ent *config[MAXLINES + 1];
|
|
|
|
char errmsg[256];
|
|
|
|
char dev[sizeof(utmpp->ut_line)];
|
|
|
|
unsigned char limit_type;
|
|
|
|
int configline = 0;
|
|
|
|
int pending_reread = 0;
|
|
|
|
int allow_reread = 0;
|
|
|
|
time_t time_now;
|
|
|
|
struct tm now;
|
|
|
|
int now_hhmm;
|
|
|
|
int daytime = 0; /* Amount of time a user has been on in current day */
|
|
|
|
char path[255]; /*seppy */
|
|
|
|
FILE *proc_file; /*seppy */
|
|
|
|
char comm[16]; /*seppy; to save the command of a pid */
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
#ifdef NEED_STRCASECMP
|
|
|
|
int strcasecmp(char *s1, char *s2)
|
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
while (*s1 && *s2) {
|
|
|
|
if (tolower(*s1) < tolower(*s2))
|
|
|
|
return -1;
|
|
|
|
else if (tolower(*s1) > tolower(*s2))
|
|
|
|
return 1;
|
|
|
|
s1++;
|
|
|
|
s2++;
|
|
|
|
}
|
|
|
|
if (*s1)
|
|
|
|
return -1;
|
|
|
|
if (*s2)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-04-02 02:15:25 +02:00
|
|
|
int main(argc, argv)
|
2020-10-31 10:10:54 +01:00
|
|
|
int argc;
|
|
|
|
char *argv[];
|
2009-01-05 07:11:58 +01:00
|
|
|
{
|
2008-04-02 02:15:25 +02:00
|
|
|
signal(SIGTERM, shut_down);
|
2009-01-05 07:11:58 +01:00
|
|
|
signal(SIGHUP, reread_config);
|
|
|
|
signal(SIGCHLD, reapchild);
|
|
|
|
signal(SIGINT, SIG_IGN);
|
|
|
|
signal(SIGQUIT, SIG_IGN);
|
2008-04-02 02:15:25 +02:00
|
|
|
signal(SIGSEGV, segfault);
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
|
|
|
|
|
|
/* The only valid invocations are "timeoutd" or "timeoutd user tty" */
|
2020-10-31 10:10:54 +01:00
|
|
|
if (argc != 1 && argc != 3) {
|
|
|
|
syslog(LOG_ERR, "Incorrect invocation of timeoutd (argc=%d) by UID %d.", argc, getuid());
|
|
|
|
exit(5);
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* read config file into memory */
|
|
|
|
read_config();
|
|
|
|
|
2008-04-02 02:15:25 +02:00
|
|
|
/* Change into the root filesystem to avoid "device busy" errors when the
|
|
|
|
* filesystem from which we were started is unmounted. /dev is convenient as
|
|
|
|
* ut_line fields are relative to it.
|
|
|
|
*/
|
2020-10-31 10:10:54 +01:00
|
|
|
if (chdir("/dev")) {
|
|
|
|
syslog(LOG_ERR, "Could not change working directory to /dev!");
|
|
|
|
exit(1);
|
2008-04-02 02:15:25 +02:00
|
|
|
}
|
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
/* Handle the "timeoutd user tty" invocation */
|
|
|
|
/* This is a bit of a shameless hack, but, well, it works. */
|
|
|
|
if (argc == 3) {
|
2008-04-02 02:15:25 +02:00
|
|
|
#ifdef DEBUG
|
2020-10-31 10:10:54 +01:00
|
|
|
syslog(SYSLOG_DEBUG, "Running in user check mode. Checking user %s on %s.", argv[1],
|
|
|
|
argv[2]);
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
2020-10-31 10:10:54 +01:00
|
|
|
strncpy(dev, argv[2], sizeof(dev) - 1);
|
|
|
|
dev[sizeof(dev) - 1] = '\0';
|
|
|
|
time_now = time((time_t *) 0); /* get current time */
|
2009-01-05 07:11:58 +01:00
|
|
|
now = *(localtime(&time_now)); /* Break it into bits */
|
|
|
|
now_hhmm = now.tm_hour * 100 + now.tm_min;
|
|
|
|
allow_reread = 0;
|
2020-10-31 10:10:54 +01:00
|
|
|
read_wtmp(); /* Read in today's wtmp entries */
|
|
|
|
switch (chk_timeout(argv[1], dev, "", 0, 0)) {
|
|
|
|
case DAYMAX:
|
|
|
|
syslog(LOG_NOTICE,
|
|
|
|
"User %s on %s exceeded maximum daily limit (%d minutes). Login check failed.",
|
|
|
|
argv[1], argv[2], config[configline]->daymax);
|
|
|
|
logoff_msg(1);
|
|
|
|
exit(10);
|
|
|
|
case NOLOGIN:
|
|
|
|
syslog(LOG_NOTICE,
|
|
|
|
"User %s not allowed to login on %s at this time. Login check failed.", argv[1],
|
|
|
|
argv[2]);
|
|
|
|
logoff_msg(1);
|
|
|
|
exit(20);
|
|
|
|
case ACTIVE:
|
2008-04-02 02:15:25 +02:00
|
|
|
#ifdef DEBUG
|
2020-10-31 10:10:54 +01:00
|
|
|
syslog(SYSLOG_DEBUG, "User %s on %s passed login check.", argv[1], argv[2]);
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
2020-10-31 10:10:54 +01:00
|
|
|
free_wtmp();
|
|
|
|
exit(0);
|
|
|
|
default:
|
|
|
|
syslog(LOG_ERR,
|
|
|
|
"Internal error checking user %s on %s - unexpected return from chk_timeout",
|
|
|
|
argv[1], argv[2]);
|
|
|
|
exit(30);
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If running in daemon mode (no parameters) */
|
2020-12-06 19:51:37 +01:00
|
|
|
pid_t pid;
|
|
|
|
|
|
|
|
if ((pid = fork()) < 0) {
|
|
|
|
syslog(LOG_ERR, "Failed to execute fork number 1");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (pid > 0)
|
|
|
|
exit(0);
|
2009-01-05 07:11:58 +01:00
|
|
|
|
2020-12-16 23:15:55 +01:00
|
|
|
struct rlimit r;
|
|
|
|
if (getrlimit(RLIMIT_NOFILE, &r) == -1) {
|
|
|
|
syslog(LOG_ERR, "Coudln't get file resource limit.");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
for (int i = r.rlim_cur; i >= 0; --i) {
|
2020-12-10 14:36:21 +01:00
|
|
|
close(i);
|
|
|
|
}
|
|
|
|
|
2020-12-06 19:51:37 +01:00
|
|
|
if (setsid() < 0) {
|
|
|
|
syslog(LOG_ERR, "Failed to set new session ID at startup.");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((pid = fork()) < 0) {
|
|
|
|
syslog(LOG_ERR, "Failed to execute fork number 2");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (pid > 0)
|
|
|
|
exit(0);
|
|
|
|
|
|
|
|
umask(0);
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
syslog(LOG_NOTICE, "Daemon started.");
|
|
|
|
|
|
|
|
/* the child processes all utmp file entries: */
|
2020-10-31 10:10:54 +01:00
|
|
|
while (1) {
|
2009-01-05 07:11:58 +01:00
|
|
|
/* Record time at which we woke up & started checking */
|
2020-10-31 10:10:54 +01:00
|
|
|
time_now = time((time_t *) 0); /* get current time */
|
2009-01-05 07:11:58 +01:00
|
|
|
now = *(localtime(&time_now)); /* Break it into bits */
|
|
|
|
now_hhmm = now.tm_hour * 100 + now.tm_min;
|
|
|
|
allow_reread = 0;
|
2020-10-31 10:10:54 +01:00
|
|
|
read_wtmp(); /* Read in today's wtmp entries */
|
|
|
|
setutent();
|
2008-04-02 02:15:25 +02:00
|
|
|
#ifdef DEBUG
|
2020-10-31 10:10:54 +01:00
|
|
|
syslog(SYSLOG_DEBUG, "Time to check utmp for exceeded limits.");
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
2009-01-05 07:11:58 +01:00
|
|
|
while ((utmpp = getutent()) != (struct utmp *) NULL)
|
|
|
|
check_idle();
|
2020-10-31 10:10:54 +01:00
|
|
|
free_wtmp(); /* Free up memory used by today's wtmp entries */
|
2009-01-05 07:11:58 +01:00
|
|
|
allow_reread = 1;
|
|
|
|
if (pending_reread)
|
2020-10-31 10:10:54 +01:00
|
|
|
reread_config(SIGHUP);
|
2008-04-02 02:15:25 +02:00
|
|
|
#ifdef DEBUG
|
2009-01-05 07:11:58 +01:00
|
|
|
syslog(SYSLOG_DEBUG, "Finished checking utmp... sleeping for 1 minute.");
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
2009-01-05 07:11:58 +01:00
|
|
|
sleep(60);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read in today's wtmp entries */
|
|
|
|
|
|
|
|
void read_wtmp()
|
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
FILE *fp;
|
|
|
|
struct utmp ut;
|
2020-11-25 19:04:56 +01:00
|
|
|
struct ut_list *ut_list_p;
|
2020-10-31 10:10:54 +01:00
|
|
|
struct tm *tm;
|
2009-01-05 07:11:58 +01:00
|
|
|
|
2008-04-02 02:15:25 +02:00
|
|
|
#ifdef DEBUG
|
2009-01-05 07:11:58 +01:00
|
|
|
syslog(SYSLOG_DEBUG, "Reading today's wtmp entries.");
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
if ((fp = fopen(WTMP_FILE, "r")) == NULL)
|
2020-10-31 10:10:54 +01:00
|
|
|
bailout("Could not open wtmp file!", 1);
|
2009-01-05 07:11:58 +01:00
|
|
|
|
2008-04-02 02:15:25 +02:00
|
|
|
#ifdef DEBUG
|
2009-01-05 07:11:58 +01:00
|
|
|
syslog(SYSLOG_DEBUG, "Seek to end of wtmp");
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
2009-01-05 07:11:58 +01:00
|
|
|
/* Go to end of file minus one structure */
|
|
|
|
fseek(fp, -1L * sizeof(struct utmp), SEEK_END);
|
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
while (fread(&ut, sizeof(struct utmp), 1, fp) == 1) {
|
|
|
|
/* ut.ut_tv.tv_sec is not guaranteed to be time_t and localtime requires a time_t
|
|
|
|
argument, and will break otherwise */
|
|
|
|
time_t tmp_time = ut.ut_tv.tv_sec;
|
|
|
|
tm = localtime(&tmp_time);
|
2009-01-05 07:11:58 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
if (tm->tm_year != now.tm_year || tm->tm_yday != now.tm_yday)
|
|
|
|
break;
|
2009-01-05 07:11:58 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
if (ut.ut_type == USER_PROCESS || ut.ut_type == DEAD_PROCESS || ut.ut_type == UT_UNKNOWN || /* SA 19940703 */
|
|
|
|
ut.ut_type == LOGIN_PROCESS || ut.ut_type == BOOT_TIME)
|
|
|
|
{
|
|
|
|
if ((ut_list_p = (struct ut_list *)
|
|
|
|
malloc(sizeof(struct ut_list))) == NULL)
|
|
|
|
bailout("Out of memory in read_wtmp.", 1);
|
|
|
|
ut_list_p->elem = ut;
|
|
|
|
ut_list_p->next = wtmplist;
|
|
|
|
wtmplist = ut_list_p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Position the file pointer 2 structures back */
|
|
|
|
if (fseek(fp, -2 * sizeof(struct utmp), SEEK_CUR) < 0)
|
|
|
|
break;
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
fclose(fp);
|
2008-04-02 02:15:25 +02:00
|
|
|
#ifdef DEBUG
|
2009-01-05 07:11:58 +01:00
|
|
|
syslog(SYSLOG_DEBUG, "Finished reading today's wtmp entries.");
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Free up memory used by today's wtmp entries */
|
|
|
|
|
|
|
|
void free_wtmp()
|
|
|
|
{
|
2020-11-25 19:04:56 +01:00
|
|
|
struct ut_list *ut_list_p;
|
2008-04-02 02:15:25 +02:00
|
|
|
#ifdef DEBUG
|
2009-01-05 07:11:58 +01:00
|
|
|
syslog(SYSLOG_DEBUG, "Freeing list of today's wtmp entries.");
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
2009-01-05 07:11:58 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
while (wtmplist) {
|
2009-01-05 07:11:58 +01:00
|
|
|
#ifdef DEBUG_WTMP
|
2020-10-31 10:10:54 +01:00
|
|
|
struct tm *tm;
|
|
|
|
tm = localtime(&(wtmplist->elem.ut_time));
|
|
|
|
printf("%d:%d %s %s %s\n", tm->tm_hour, tm->tm_min, wtmplist->elem.ut_line,
|
|
|
|
wtmplist->elem.ut_user,
|
|
|
|
wtmplist->elem.ut_type ==
|
2020-12-17 17:01:15 +01:00
|
|
|
LOGIN_PROCESS ? "login" : wtmplist->elem.ut_type == BOOT_TIME ? "reboot" : "logoff");
|
2009-01-05 07:11:58 +01:00
|
|
|
#endif
|
|
|
|
ut_list_p = wtmplist;
|
|
|
|
wtmplist = wtmplist->next;
|
|
|
|
free(ut_list_p);
|
|
|
|
}
|
2008-04-02 02:15:25 +02:00
|
|
|
#ifdef DEBUG
|
2009-01-05 07:11:58 +01:00
|
|
|
syslog(SYSLOG_DEBUG, "Finished freeing list of today's wtmp entries.");
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
void store_times(t, time_str)
|
2009-01-05 07:11:58 +01:00
|
|
|
struct time_ent **t;
|
|
|
|
char *time_str;
|
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
int i = 0;
|
|
|
|
int ar_size = 2;
|
|
|
|
char *p;
|
|
|
|
struct time_ent *te;
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
while (time_str[i])
|
2020-10-31 10:10:54 +01:00
|
|
|
if (time_str[i++] == ',')
|
|
|
|
ar_size++;
|
2009-01-05 07:11:58 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
if ((*t = (struct time_ent *) malloc(ar_size * sizeof(struct time_ent))) == NULL)
|
|
|
|
bailout("Out of memory", 1);
|
2009-01-05 07:11:58 +01:00
|
|
|
te = *t;
|
|
|
|
|
|
|
|
p = strtok(time_str, ",");
|
|
|
|
/* For each day/timerange set, */
|
2020-10-31 10:10:54 +01:00
|
|
|
while (p) {
|
2009-01-05 07:11:58 +01:00
|
|
|
/* Store valid days */
|
2020-10-31 10:10:54 +01:00
|
|
|
te->days = 0;
|
|
|
|
while (isalpha(*p)) {
|
|
|
|
if (!p[1] || !isalpha(p[1])) {
|
|
|
|
syslog(LOG_ERR,
|
|
|
|
"Malformed day name (%c%c) in time field of config file (%s). Entry ignored.",
|
|
|
|
p[0], p[1], CONFIG);
|
|
|
|
(*t)->days = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
*p = toupper(*p);
|
|
|
|
p[1] = toupper(p[1]);
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
while (daynames[i]) {
|
|
|
|
if (!strncmp(daynames[i], p, 2)) {
|
|
|
|
te->days |= daynums[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (!daynames[i]) {
|
|
|
|
syslog(LOG_ERR,
|
|
|
|
"Malformed day name (%c%c) in time field of config file (%s). Entry ignored.",
|
|
|
|
p[0], p[1], CONFIG);
|
|
|
|
(*t)->days = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
p += 2;
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Store start and end times */
|
2020-10-31 10:10:54 +01:00
|
|
|
if (*p) {
|
|
|
|
if (strlen(p) != 9 || p[4] != '-') {
|
|
|
|
syslog(LOG_ERR,
|
|
|
|
"Malformed time (%s) in time field of config file (%s). Entry ignored.", p,
|
|
|
|
CONFIG);
|
|
|
|
(*t)->days = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
te->starttime = atoi(p);
|
|
|
|
te->endtime = atoi(p + 5);
|
|
|
|
if ((te->starttime == 0 && strncmp(p, "0000-", 5))
|
|
|
|
|| (te->endtime == 0 && strcmp(p + 5, "0000"))) {
|
|
|
|
syslog(LOG_ERR,
|
|
|
|
"Invalid range (%s) in time field of config file (%s). Entry ignored.", p,
|
|
|
|
CONFIG);
|
|
|
|
(*t)->days = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
te->starttime = 0;
|
|
|
|
te->endtime = 2359;
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
2020-10-31 10:10:54 +01:00
|
|
|
p = strtok(NULL, ",");
|
|
|
|
te++;
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
te->days = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void alloc_cp(a, b)
|
|
|
|
char **a;
|
|
|
|
char *b;
|
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
if ((*a = (char *) malloc(strlen(b) + 1)) == NULL)
|
|
|
|
bailout("Out of memory", 1);
|
|
|
|
else
|
|
|
|
strcpy(*a, b);
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
|
2008-04-02 02:15:25 +02:00
|
|
|
void read_config()
|
2009-01-05 07:11:58 +01:00
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
FILE *config_file;
|
|
|
|
char *p;
|
|
|
|
char *lstart;
|
|
|
|
int i = 0;
|
2008-04-02 02:15:25 +02:00
|
|
|
#ifdef DEBUG
|
2020-10-31 10:10:54 +01:00
|
|
|
int j = 0;
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
2020-10-31 10:10:54 +01:00
|
|
|
char line[256];
|
|
|
|
char *tok;
|
|
|
|
int linenum = 0;
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
if ((config_file = fopen(CONFIG, "r")) == NULL)
|
2020-10-31 10:10:54 +01:00
|
|
|
bailout("Cannot open config file", 1);
|
|
|
|
|
|
|
|
while (fgets(line, 256, config_file) != NULL) {
|
|
|
|
linenum++;
|
|
|
|
p = line;
|
|
|
|
while (*p && (*p == ' ' || *p == '\t'))
|
|
|
|
p++;
|
|
|
|
lstart = p;
|
|
|
|
while (*p && *p != '#' && *p != '\n')
|
|
|
|
p++;
|
|
|
|
*p = '\0';
|
|
|
|
if (*lstart) {
|
|
|
|
if (i == MAXLINES)
|
|
|
|
bailout("Too many lines in timeouts config file.", 1);
|
|
|
|
if ((config[i] = (struct config_ent *)
|
|
|
|
malloc(sizeof(struct config_ent)))
|
|
|
|
== NULL)
|
|
|
|
bailout("Out of memory", 1);
|
|
|
|
config[i]->times = NULL;
|
|
|
|
config[i]->ttys = NULL;
|
|
|
|
config[i]->users = NULL;
|
|
|
|
config[i]->groups = NULL;
|
|
|
|
config[i]->login_allowed = 1;
|
|
|
|
config[i]->idlemax = -1;
|
|
|
|
config[i]->sessmax = -1;
|
|
|
|
config[i]->daymax = -1;
|
|
|
|
config[i]->warntime = 5;
|
|
|
|
config[i]->messages[IDLEMSG] = NULL;
|
|
|
|
config[i]->messages[SESSMSG] = NULL;
|
|
|
|
config[i]->messages[DAYMSG] = NULL;
|
|
|
|
config[i]->messages[NOLOGINMSG] = NULL;
|
|
|
|
if ((tok = strsep(&lstart, ":")) != NULL)
|
|
|
|
store_times(&config[i]->times, tok);
|
|
|
|
if ((tok = strsep(&lstart, ":")) != NULL)
|
|
|
|
alloc_cp(&config[i]->ttys, tok);
|
|
|
|
if ((tok = strsep(&lstart, ":")) != NULL)
|
|
|
|
alloc_cp(&config[i]->users, tok);
|
|
|
|
if ((tok = strsep(&lstart, ":")) != NULL)
|
|
|
|
alloc_cp(&config[i]->groups, tok);
|
|
|
|
tok = strsep(&lstart, ":");
|
|
|
|
if (tok != NULL && !strncasecmp(tok, "NOLOGIN", 7)) {
|
|
|
|
config[i]->login_allowed = 0;
|
|
|
|
if (tok[7] == ';')
|
|
|
|
alloc_cp(&config[i]->messages[NOLOGINMSG], tok + 8);
|
|
|
|
else if ((tok = strsep(&lstart, ":")) != NULL)
|
|
|
|
alloc_cp(&config[i]->messages[NOLOGINMSG], tok);
|
|
|
|
} else if (tok != NULL && !strcasecmp(tok, "LOGIN"))
|
|
|
|
config[i]->login_allowed = 1;
|
|
|
|
else {
|
|
|
|
if (tok != NULL) {
|
|
|
|
config[i]->idlemax = atoi(tok);
|
|
|
|
if ((p = strchr(tok, ';')) != NULL)
|
|
|
|
alloc_cp(&config[i]->messages[IDLEMSG], p + 1);
|
|
|
|
}
|
|
|
|
if ((tok = strsep(&lstart, ":")) != NULL) {
|
|
|
|
config[i]->sessmax = atoi(tok);
|
|
|
|
if ((p = strchr(tok, ';')) != NULL)
|
|
|
|
alloc_cp(&config[i]->messages[SESSMSG], p + 1);
|
|
|
|
}
|
|
|
|
if ((tok = strsep(&lstart, ":")) != NULL) {
|
|
|
|
config[i]->daymax = atoi(tok);
|
|
|
|
if ((p = strchr(tok, ';')) != NULL)
|
|
|
|
alloc_cp(&config[i]->messages[DAYMSG], p + 1);
|
|
|
|
}
|
|
|
|
if ((tok = strsep(&lstart, ":")) != NULL) {
|
|
|
|
config[i]->warntime = atoi(tok);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!config[i]->times || !config[i]->ttys || !config[i]->users || !config[i]->groups) {
|
|
|
|
syslog(LOG_ERR, "Error on line %d of config file (%s). Line ignored.", linenum,
|
|
|
|
CONFIG);
|
|
|
|
} else
|
|
|
|
i++;
|
|
|
|
}
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
config[i] = NULL;
|
|
|
|
|
|
|
|
if (fclose(config_file) == EOF)
|
2020-10-31 10:10:54 +01:00
|
|
|
bailout("Cannot close config file", 1);
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2020-10-31 10:10:54 +01:00
|
|
|
i = 0;
|
|
|
|
while (config[i]) {
|
|
|
|
printf("line %d: ", i);
|
|
|
|
j = 0;
|
|
|
|
while (config[i]->times[j].days)
|
|
|
|
printf("%d(%d-%d):", config[i]->times[j].days,
|
|
|
|
config[i]->times[j].starttime, config[i]->times[j].endtime), j++;
|
|
|
|
printf("%s:%s:%s:%s:%d;%s:%d;%s:%d;%s:%d\n",
|
|
|
|
config[i]->ttys,
|
|
|
|
config[i]->users,
|
|
|
|
config[i]->groups,
|
|
|
|
config[i]->login_allowed ? "LOGIN" : "NOLOGIN",
|
|
|
|
config[i]->idlemax,
|
|
|
|
config[i]->messages[IDLEMSG] ==
|
|
|
|
NULL ? "builtin" : config[i]->messages[IDLEMSG],
|
|
|
|
config[i]->sessmax,
|
|
|
|
config[i]->messages[SESSMSG] ==
|
|
|
|
NULL ? "builtin" : config[i]->messages[SESSMSG],
|
|
|
|
config[i]->daymax,
|
|
|
|
config[i]->messages[DAYMSG] == NULL ? "builtin" : config[i]->messages[DAYMSG],
|
|
|
|
config[i]->warntime), i++;
|
|
|
|
}
|
|
|
|
printf("End debug output.\n");
|
|
|
|
#endif /* DEBUG */
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
char chktimes(te)
|
|
|
|
struct time_ent *te;
|
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
while (te->days) {
|
|
|
|
if (daynums[now.tm_wday] & te->days && /* Date within range */
|
|
|
|
((te->starttime <= te->endtime && /* Time within range */
|
|
|
|
now_hhmm >= te->starttime && now_hhmm <= te->endtime)
|
|
|
|
|| (te->starttime > te->endtime
|
|
|
|
&& (now_hhmm >= te->starttime || now_hhmm <= te->endtime))))
|
|
|
|
return 1;
|
2009-01-05 07:11:58 +01:00
|
|
|
te++;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char chkmatch(element, in_set)
|
|
|
|
char *element;
|
|
|
|
char *in_set;
|
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
char *t;
|
|
|
|
char *set = (char *) malloc(strlen(in_set) + 1);
|
2009-01-05 07:11:58 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
if (set == NULL)
|
|
|
|
bailout("Out of memory", 1);
|
|
|
|
else
|
|
|
|
strcpy(set, in_set);
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
t = strtok(set, " ,");
|
2020-10-31 10:10:54 +01:00
|
|
|
while (t) {
|
|
|
|
if (t[strlen(t) - 1] == '*') {
|
|
|
|
if (!strncmp(t, element, strlen(t) - 1)) {
|
|
|
|
free(set);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
} else if (!strcmp(t, element)) {
|
|
|
|
free(set);
|
|
|
|
return 1;
|
|
|
|
}
|
2009-01-05 07:11:58 +01:00
|
|
|
t = strtok(NULL, " ,");
|
|
|
|
}
|
|
|
|
free(set);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the number of minutes which user has been logged in for on
|
|
|
|
* any of the ttys specified in config[configline] during the current day.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void get_day_time(user)
|
|
|
|
char *user;
|
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
struct ut_list *login_p;
|
|
|
|
struct ut_list *logout_p;
|
|
|
|
struct ut_list *prev_p;
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
daytime = 0;
|
|
|
|
login_p = wtmplist;
|
|
|
|
while (login_p)
|
|
|
|
{
|
|
|
|
/* For each login on a matching tty find its logout */
|
2020-12-17 17:01:15 +01:00
|
|
|
if (login_p->elem.ut_type == USER_PROCESS && !strncmp(login_p->elem.ut_user, user, 8)
|
2020-10-31 10:10:54 +01:00
|
|
|
&& chkmatch(login_p->elem.ut_line, config[configline]->ttys)) {
|
2009-01-05 07:11:58 +01:00
|
|
|
#ifdef DEBUG_WTMP
|
2020-10-31 10:10:54 +01:00
|
|
|
struct tm *tm;
|
|
|
|
tm = localtime(&(login_p->elem.ut_time));
|
|
|
|
fprintf(stderr, "%d:%d %s %s %s\n",
|
|
|
|
tm->tm_hour, tm->tm_min, login_p->elem.ut_line, login_p->elem.ut_user, "login");
|
2009-01-05 07:11:58 +01:00
|
|
|
#endif
|
|
|
|
prev_p = logout_p = login_p->next;
|
2020-10-31 10:10:54 +01:00
|
|
|
while (logout_p) {
|
2009-01-05 07:11:58 +01:00
|
|
|
/*
|
|
|
|
* SA19931128
|
|
|
|
* If there has been a crash, then be reasonably fair and use the
|
|
|
|
* last recorded login/logout as the user's logout time. This will
|
|
|
|
* potentially allow them slightly more online time than usual,
|
|
|
|
* but is better than marking them as logged in for the time the machine
|
|
|
|
* was down.
|
|
|
|
*/
|
2020-10-31 10:10:54 +01:00
|
|
|
if (logout_p->elem.ut_type == BOOT_TIME) {
|
|
|
|
logout_p = prev_p;
|
|
|
|
break;
|
|
|
|
}
|
2020-12-17 17:07:56 +01:00
|
|
|
if (!strncmp(login_p->elem.ut_line, logout_p->elem.ut_line, UT_LINESIZE))
|
2020-10-31 10:10:54 +01:00
|
|
|
break;
|
2009-01-05 07:11:58 +01:00
|
|
|
prev_p = logout_p;
|
|
|
|
logout_p = logout_p->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_WTMP
|
2020-10-31 10:10:54 +01:00
|
|
|
if (logout_p) {
|
|
|
|
tm = localtime(&(logout_p->elem.ut_time));
|
|
|
|
fprintf(stderr, "%d:%d %s %s %s\n",
|
|
|
|
tm->tm_hour, tm->tm_min, logout_p->elem.ut_line, logout_p->elem.ut_user,
|
|
|
|
"logout");
|
|
|
|
fprintf(stderr, "%s %d minutes\n", user,
|
|
|
|
((logout_p ? logout_p->elem.ut_time : time_now) -
|
|
|
|
login_p->elem.ut_time) / 60);
|
|
|
|
}
|
2009-01-05 07:11:58 +01:00
|
|
|
#endif
|
2020-10-31 10:10:54 +01:00
|
|
|
daytime += (logout_p ? logout_p->elem.ut_time : time_now) - login_p->elem.ut_time;
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
login_p = login_p->next;
|
|
|
|
}
|
|
|
|
daytime /= 60;
|
|
|
|
#ifdef DEBUG
|
2020-10-31 10:10:54 +01:00
|
|
|
fprintf(stderr, "%s has been logged in for %d minutes today.\n", user, daytime);
|
2009-01-05 07:11:58 +01:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-04-02 02:15:25 +02:00
|
|
|
void warnpending(tty, time_remaining, user, host)
|
2009-01-05 07:11:58 +01:00
|
|
|
char *tty;
|
|
|
|
int time_remaining;
|
2008-04-02 02:15:25 +02:00
|
|
|
char *user;
|
|
|
|
char *host;
|
2009-01-05 07:11:58 +01:00
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
int fd;
|
|
|
|
FILE *ttyf;
|
|
|
|
char cmdbuf[1024];
|
2009-01-05 07:11:58 +01:00
|
|
|
|
2008-04-02 02:15:25 +02:00
|
|
|
#ifdef DEBUG
|
2020-10-31 10:10:54 +01:00
|
|
|
syslog(SYSLOG_DEBUG, "Warning %s@%s on %s of pending logoff in %d minutes.", user, host, tty,
|
|
|
|
time_remaining);
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
if (chk_xsession(tty, host)) {
|
|
|
|
syslog(SYSLOG_DEBUG,
|
|
|
|
"Warning %s running X on %s for pending logout! (%d min%s left)",
|
|
|
|
user, tty, time_remaining, time_remaining == 1 ? "" : "s");
|
|
|
|
|
|
|
|
/* then send the message using xmessage */
|
|
|
|
/* well, this is not really clean: */
|
|
|
|
sprintf(cmdbuf,
|
|
|
|
"su %s -c \"xmessage -display %s -center 'WARNING: You will be logged out in %d minute%s when your %s limit expires.'&\"",
|
|
|
|
user, host, time_remaining, time_remaining == 1 ? "" : "s",
|
|
|
|
limit_names[limit_type]);
|
|
|
|
system(cmdbuf);
|
|
|
|
/*#ifdef DEBUG */
|
|
|
|
syslog(LOG_DEBUG, "cmdbuf=%s", cmdbuf);
|
|
|
|
/*#endif */
|
|
|
|
sleep(KWAIT); /* and give the user some time to read the message ;) */
|
|
|
|
return;
|
2008-04-02 02:15:25 +02:00
|
|
|
}
|
2020-10-30 21:56:33 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
if ((fd = open(tty, O_WRONLY | O_NOCTTY | O_NONBLOCK)) < 0 || (ttyf = fdopen(fd, "w")) == NULL) {
|
|
|
|
syslog(LOG_ERR, "Could not open %s to warn of impending logoff.\n", tty);
|
2009-01-05 07:11:58 +01:00
|
|
|
return;
|
|
|
|
}
|
2020-10-31 10:10:54 +01:00
|
|
|
fprintf(ttyf,
|
2020-10-31 17:49:50 +01:00
|
|
|
"\a\r\nWARNING:\r\nYou will be logged out in %d minute%s when your %s limit expires.\r\n",
|
2020-10-31 10:10:54 +01:00
|
|
|
time_remaining, time_remaining == 1 ? "" : "s", limit_names[limit_type]);
|
2009-01-05 07:11:58 +01:00
|
|
|
fclose(ttyf);
|
|
|
|
}
|
|
|
|
|
|
|
|
char chk_timeout(user, dev, host, idle, session)
|
|
|
|
char *user;
|
|
|
|
char *dev;
|
|
|
|
char *host;
|
|
|
|
int idle;
|
|
|
|
int session;
|
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
struct passwd *pw;
|
|
|
|
struct group *gr;
|
|
|
|
struct group *secgr;
|
|
|
|
char timematch = 0;
|
|
|
|
char ttymatch = 0;
|
|
|
|
char usermatch = 0;
|
|
|
|
char groupmatch = 0;
|
|
|
|
char *tty = dev;
|
|
|
|
char **p;
|
|
|
|
int disc;
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
configline = 0;
|
|
|
|
|
|
|
|
/* Find primary group for specified user */
|
2020-10-31 10:10:54 +01:00
|
|
|
if ((pw = getpwnam(user)) == NULL) {
|
|
|
|
syslog(LOG_ERR, "Could not get password entry for %s.", user);
|
|
|
|
return 0;
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
2020-10-31 10:10:54 +01:00
|
|
|
if ((gr = getgrgid(pw->pw_gid)) == NULL) {
|
|
|
|
syslog(LOG_ERR, "Could not get group name for %s.", user);
|
|
|
|
return 0;
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
|
2008-04-02 02:15:25 +02:00
|
|
|
#ifdef DEBUG
|
2009-01-05 07:11:58 +01:00
|
|
|
syslog(SYSLOG_DEBUG, "Checking user %s group %s tty %s.", user, gr->gr_name, tty);
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
/* Check to see if current user matches any entry based on tty/user/group */
|
2020-10-31 10:10:54 +01:00
|
|
|
while (config[configline]) {
|
|
|
|
timematch = chktimes(config[configline]->times);
|
2009-01-05 07:11:58 +01:00
|
|
|
ttymatch = chkmatch(tty, config[configline]->ttys);
|
|
|
|
usermatch = chkmatch(user, config[configline]->users);
|
|
|
|
groupmatch = chkmatch(gr->gr_name, config[configline]->groups);
|
|
|
|
/* If the primary group doesn't match this entry, check secondaries */
|
2020-10-31 10:10:54 +01:00
|
|
|
setgrent();
|
|
|
|
while (!groupmatch && (secgr = getgrent()) != NULL) {
|
|
|
|
p = secgr->gr_mem;
|
|
|
|
while (*p && !groupmatch) {
|
|
|
|
if (!strcmp(*p, user))
|
|
|
|
groupmatch = chkmatch(secgr->gr_name, config[configline]->groups);
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
2009-01-05 07:11:58 +01:00
|
|
|
/* If so, then check their idle, daily and session times in turn */
|
2020-10-31 10:10:54 +01:00
|
|
|
if (timematch && ttymatch && usermatch && groupmatch) {
|
|
|
|
get_day_time(user);
|
2008-04-02 02:15:25 +02:00
|
|
|
#ifdef DEBUG
|
2020-10-31 10:10:54 +01:00
|
|
|
syslog(SYSLOG_DEBUG, "Matched entry %d", configline);
|
|
|
|
syslog(SYSLOG_DEBUG,
|
|
|
|
"Idle=%d (max=%d) Sess=%d (max=%d) Daily=%d (max=%d) warntime=%d",
|
|
|
|
idle, config[configline]->idlemax, session,
|
|
|
|
config[configline]->sessmax, daytime, config[configline]->daymax,
|
|
|
|
config[configline]->warntime);
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
2020-10-31 10:10:54 +01:00
|
|
|
disc = getdisc(dev, host);
|
2009-01-05 07:11:58 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
limit_type = NOLOGINMSG;
|
|
|
|
if (!config[configline]->login_allowed)
|
|
|
|
return NOLOGIN;
|
2009-01-05 07:11:58 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
limit_type = IDLEMSG;
|
|
|
|
if (disc == N_TTY && config[configline]->idlemax > 0
|
|
|
|
&& idle >= config[configline]->idlemax)
|
|
|
|
return IDLEMAX;
|
2009-01-05 07:11:58 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
limit_type = SESSMSG;
|
|
|
|
if (config[configline]->sessmax > 0 && session >= config[configline]->sessmax)
|
|
|
|
return SESSMAX;
|
2009-01-05 07:11:58 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
limit_type = DAYMSG;
|
|
|
|
if (config[configline]->daymax > 0 && daytime >= config[configline]->daymax)
|
|
|
|
return DAYMAX;
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
/* If none of those have been exceeded, then warn users of upcoming logouts */
|
2020-10-31 10:10:54 +01:00
|
|
|
limit_type = DAYMSG;
|
|
|
|
if (config[configline]->daymax > 0
|
|
|
|
&& daytime >= config[configline]->daymax - config[configline]->warntime)
|
|
|
|
warnpending(dev, config[configline]->daymax - daytime, user, host);
|
|
|
|
else {
|
|
|
|
limit_type = SESSMSG;
|
|
|
|
if (config[configline]->sessmax > 0
|
|
|
|
&& session >= config[configline]->sessmax - config[configline]->warntime)
|
|
|
|
warnpending(dev, config[configline]->sessmax - session, user, host);
|
|
|
|
}
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
/* Otherwise, leave the poor net addict alone */
|
2020-10-31 10:10:54 +01:00
|
|
|
return ACTIVE;
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
configline++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If they do not match any entries, then they can stay on forever */
|
|
|
|
return ACTIVE;
|
|
|
|
}
|
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
void check_idle()
|
|
|
|
{ /* Check for exceeded time limits & logoff exceeders */
|
|
|
|
char user[sizeof(utmpp->ut_user)];
|
|
|
|
char host[sizeof(utmpp->ut_host)];
|
2009-01-05 07:11:58 +01:00
|
|
|
struct stat status, *pstat;
|
2020-11-25 17:20:58 +01:00
|
|
|
time_t idle, sesstime;
|
2020-10-31 10:10:54 +01:00
|
|
|
short aktconfigline = -1; /* -1 if user is in config; >0 if he's not in config, * is handled in an other way */
|
2009-01-05 07:11:58 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
pstat = &status; /* point to status structure */
|
2009-01-05 07:12:25 +01:00
|
|
|
sprintf(path, "/proc/%d", utmpp->ut_pid);
|
|
|
|
if (utmpp->ut_type != USER_PROCESS || !utmpp->ut_user[0] || /* if not user process */
|
2020-10-31 10:10:54 +01:00
|
|
|
stat(path, pstat)) /* or if proc doesn't exist */
|
|
|
|
return; /* skip the utmp entry */
|
|
|
|
strncpy(user, utmpp->ut_user, sizeof(user) - 1); /* get user name */
|
|
|
|
user[sizeof(user) - 1] = '\0'; /* null terminate user name string */
|
2008-04-02 02:15:25 +02:00
|
|
|
|
|
|
|
|
|
|
|
/* Only check user if he is mentioned in the config */
|
2020-10-30 21:56:33 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
if (!config[0])
|
|
|
|
return; /* no entries in config */
|
|
|
|
while (config[++aktconfigline] && aktconfigline >= 0)
|
Fix "no * expansion for USERS field in config" bug
There were two lines in the check_idle() function, which were meant to
test if a given user has been found in a given line of the configuration
file. Rather than using the chkmatch function, to test for a match, and
any potential expansions, these two lines, comprising an if statement,
simply checked if the USER pattern matched the given username as a
string, or if it was simply a *.
This means that if a function was checking the user kappa, it would
match him for the USERS field "kappa" or "*", but not "ka*", this is not
the behaviour documented in the timeouts(5) manpage, which explicitly
states the expansion for the USERS field in the config, will be done in
the exact same way as the TTYS field.
2020-11-24 23:29:01 +01:00
|
|
|
if (chkmatch(user, config[aktconfigline]->users)) {
|
|
|
|
aktconfigline = -2; /* we found user in config, so he/they has/have restrictions */
|
2020-10-31 10:10:54 +01:00
|
|
|
break;
|
|
|
|
}
|
2020-10-30 21:56:33 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
if (aktconfigline > 0) { /* > 0 if user is not in config */
|
2008-04-02 02:15:25 +02:00
|
|
|
#ifdef DEBUG
|
2020-10-31 10:10:54 +01:00
|
|
|
syslog(SYSLOG_DEBUG, "User %s or * not in config -> No restrictions. Not checking %s on %s",
|
|
|
|
user, user, dev);
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
2020-10-31 10:10:54 +01:00
|
|
|
return; /* now, we return because the user beeing checked is not in config, so he has no restrictions */
|
2008-04-02 02:15:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
strncpy(host, utmpp->ut_host, sizeof(host) - 1); /* get host name */
|
2008-04-02 02:15:25 +02:00
|
|
|
host[sizeof(host) - 1] = '\0';
|
2020-10-31 10:10:54 +01:00
|
|
|
strncpy(dev, utmpp->ut_line, sizeof(dev) - 1); /* get device name */
|
2008-04-02 02:15:25 +02:00
|
|
|
dev[sizeof(dev) - 1] = '\0';
|
2009-01-05 07:12:25 +01:00
|
|
|
sprintf(path, "/dev/%s", dev);
|
2020-10-31 10:10:54 +01:00
|
|
|
if (stat(path, pstat) && chk_xsession(dev, host) != TIMEOUTD_XSESSION_LOCAL) { /* if can't get status for
|
|
|
|
port && if it's not a local Xsession */
|
|
|
|
sprintf(errmsg, "Can't get status of user %s's terminal (%s)\n", user, dev);
|
|
|
|
/* bailout(errmsg, 1); MOH: is there a reason to exit here? */
|
|
|
|
return;
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
/* idle time is the lesser of:
|
|
|
|
* current time less last access time OR
|
|
|
|
* current time less last modified time
|
|
|
|
*/
|
2020-10-30 21:56:33 +01:00
|
|
|
#ifdef TIMEOUTDX11
|
2020-10-31 10:10:54 +01:00
|
|
|
if (chk_xsession(dev, host) && !chk_xterm(dev, host)) { /* check idle for Xsession, but not for xterm */
|
|
|
|
idle = get_xidle(user, host) / 1000 / 60; /* get_xidle returns millisecs, we need mins */
|
|
|
|
syslog(SYSLOG_DEBUG, "get_xidle(%s,%s) returned %d mins idle for %s.", dev, host,
|
|
|
|
(int) idle, user);
|
|
|
|
} else if (chk_xterm(dev, host))
|
|
|
|
return;
|
2008-04-02 02:15:25 +02:00
|
|
|
else
|
|
|
|
#endif
|
2020-10-31 10:10:54 +01:00
|
|
|
idle = (time_now - max(pstat->st_atime, pstat->st_mtime)) / 60;
|
2008-04-02 02:15:25 +02:00
|
|
|
|
2009-01-05 07:11:58 +01:00
|
|
|
sesstime = (time_now - utmpp->ut_time) / 60;
|
2020-10-31 10:10:54 +01:00
|
|
|
switch (chk_timeout(user, dev, host, idle, sesstime)) {
|
|
|
|
case ACTIVE:
|
|
|
|
#ifdef DEBUG
|
|
|
|
syslog(SYSLOG_DEBUG, "User %s is active.", user);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case IDLEMAX:
|
|
|
|
syslog(LOG_NOTICE,
|
|
|
|
"User %s exceeded idle limit (idle for %ld minutes, max=%d).\n",
|
|
|
|
user, idle, config[configline]->idlemax);
|
|
|
|
killit(utmpp->ut_pid, user, dev, host);
|
|
|
|
break;
|
|
|
|
case SESSMAX:
|
|
|
|
syslog(LOG_NOTICE,
|
|
|
|
"User %s exceeded maximum session limit at %s (on for %ld minutes, max=%d).\n",
|
|
|
|
user, dev, sesstime, config[configline]->sessmax);
|
|
|
|
killit(utmpp->ut_pid, user, dev, host);
|
|
|
|
break;
|
|
|
|
case DAYMAX:
|
|
|
|
syslog(LOG_NOTICE,
|
|
|
|
"User %s exceeded maximum daily limit (on for %d minutes, max=%d).\n",
|
|
|
|
user, daytime, config[configline]->daymax);
|
|
|
|
killit(utmpp->ut_pid, user, dev, host);
|
|
|
|
break;
|
|
|
|
case NOLOGIN:
|
2009-01-05 07:11:58 +01:00
|
|
|
#ifdef DEBUG
|
2020-10-31 10:10:54 +01:00
|
|
|
syslog(LOG_NOTICE, "NOLOGIN period reached for user %s@%s. (pid %d)", user, host,
|
|
|
|
utmpp->ut_pid);
|
|
|
|
#else
|
|
|
|
syslog(LOG_NOTICE, "NOLOGIN period reached for user %s %s", user, host);
|
2009-01-05 07:11:58 +01:00
|
|
|
#endif
|
2020-10-31 10:10:54 +01:00
|
|
|
killit(utmpp->ut_pid, user, dev, host);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
syslog(LOG_ERR, "Internal error - unexpected return from chk_timeout");
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
void bailout(message, status) /* display error message and exit */
|
|
|
|
int status; /* exit status */
|
|
|
|
char *message; /* pointer to the error message */
|
2009-01-05 07:11:58 +01:00
|
|
|
{
|
|
|
|
syslog(LOG_ERR, "Exiting - %s", message);
|
|
|
|
exit(status);
|
|
|
|
}
|
|
|
|
|
2008-04-02 02:15:25 +02:00
|
|
|
void shut_down(signum)
|
2009-01-05 07:11:58 +01:00
|
|
|
int signum;
|
|
|
|
{
|
|
|
|
syslog(LOG_NOTICE, "Received SIGTERM.. exiting.");
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2008-04-02 02:15:25 +02:00
|
|
|
void segfault(signum)
|
|
|
|
int signum;
|
|
|
|
{
|
|
|
|
syslog(LOG_NOTICE, "Received SIGSEGV.. Something went wrong! Exiting!");
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2009-01-05 07:11:58 +01:00
|
|
|
void logoff_msg(tty)
|
|
|
|
int tty;
|
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
FILE *msgfile = NULL;
|
|
|
|
char msgbuf[1024];
|
|
|
|
int cnt;
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
if (config[configline]->messages[limit_type])
|
2020-10-31 10:10:54 +01:00
|
|
|
msgfile = fopen(config[configline]->messages[limit_type], "r");
|
|
|
|
|
|
|
|
if (msgfile) {
|
|
|
|
while ((cnt = read(tty, msgbuf, 1024)) > 0)
|
|
|
|
write(tty, msgbuf, cnt);
|
|
|
|
fclose(msgfile);
|
|
|
|
} else {
|
|
|
|
if (limit_type == NOLOGINMSG)
|
|
|
|
sprintf(msgbuf,
|
2020-10-31 17:49:50 +01:00
|
|
|
"\a\r\n\r\nLogins not allowed at this time. Please try again later.\r\n");
|
2020-10-31 10:10:54 +01:00
|
|
|
else
|
|
|
|
sprintf(msgbuf,
|
2020-10-31 17:49:50 +01:00
|
|
|
"\a\r\n\r\nYou have exceeded your %s time limit. Logging you off now.\r\n\r\n\a",
|
2020-10-31 10:10:54 +01:00
|
|
|
limit_names[limit_type]);
|
|
|
|
write(tty, msgbuf, strlen(msgbuf));
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* terminate process using SIGHUP, then SIGKILL */
|
2008-04-02 02:15:25 +02:00
|
|
|
void killit(pid, user, dev, host)
|
2009-01-05 07:11:58 +01:00
|
|
|
int pid;
|
|
|
|
char *user;
|
|
|
|
char *dev;
|
2008-04-02 02:15:25 +02:00
|
|
|
char *host;
|
2009-01-05 07:11:58 +01:00
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
int tty;
|
2008-04-02 02:15:25 +02:00
|
|
|
pid_t cpid;
|
2009-01-05 07:11:58 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
if (chk_xsession(dev, host) && !chk_xterm(dev, host)) {
|
|
|
|
killit_xsession(utmpp->ut_pid, user, host);
|
|
|
|
return;
|
2008-04-02 02:15:25 +02:00
|
|
|
}
|
2009-01-05 07:11:58 +01:00
|
|
|
/* Tell user which limit they have exceeded and that they will be logged off */
|
2020-10-31 10:10:54 +01:00
|
|
|
if ((tty = open(dev, O_WRONLY | O_NOCTTY | O_NONBLOCK)) < 0) {
|
2009-01-05 07:11:58 +01:00
|
|
|
syslog(LOG_ERR, "Could not write logoff message to %s.", dev);
|
2020-10-31 10:10:54 +01:00
|
|
|
return;
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
2020-10-30 21:56:33 +01:00
|
|
|
|
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
/* check if the pid is sshd. If so, get PID of the child process (another ssh, owned by the user).
|
|
|
|
Test reverse if this child process is also ssh and owned by the user we want to log out.
|
|
|
|
(because we don't want to slay another user ;) */
|
|
|
|
cpid = getcpid(pid);
|
2008-04-02 02:15:25 +02:00
|
|
|
#ifdef DEBUG
|
2020-10-31 10:10:54 +01:00
|
|
|
syslog(LOG_NOTICE, "I am at killit() pid=%d user=%s child=%d line %d", pid, user, cpid,
|
|
|
|
__LINE__);
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
2020-10-30 21:56:33 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
if (chk_ssh(pid) && chk_ssh(cpid) && !strcmp(getusr(cpid), user)) {
|
2008-04-02 02:15:25 +02:00
|
|
|
#ifdef DEBUG
|
2020-10-31 10:10:54 +01:00
|
|
|
syslog(LOG_NOTICE, "User %s (pid:%d, cpid:%d) logged in via ssh from %s.", user, pid, cpid,
|
|
|
|
host);
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
2020-10-31 10:10:54 +01:00
|
|
|
pid = cpid;
|
|
|
|
}
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
logoff_msg(tty);
|
2020-10-31 10:10:54 +01:00
|
|
|
sleep(KWAIT); /*make sure msg does not get lost, again (esp. ssh) */
|
2009-01-05 07:11:58 +01:00
|
|
|
close(tty);
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2020-10-31 10:10:54 +01:00
|
|
|
syslog(LOG_NOTICE, "Would normally kill pid %d user %s on %s", pid, user, dev);
|
2009-01-05 07:11:58 +01:00
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
if (fork()) /* the parent process */
|
|
|
|
return; /* returns */
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
/* Wait a little while in case the above message gets lost during logout */
|
2020-10-31 10:10:54 +01:00
|
|
|
kill(pid, SIGHUP); /* first send "hangup" signal */
|
2009-01-05 07:11:58 +01:00
|
|
|
sleep(KWAIT);
|
2020-10-31 10:10:54 +01:00
|
|
|
if (!kill(pid, 0)) { /* SIGHUP might be ignored */
|
|
|
|
kill(pid, SIGKILL); /* then send sure "kill" signal */
|
2009-01-05 07:11:58 +01:00
|
|
|
sleep(KWAIT);
|
2020-10-31 10:10:54 +01:00
|
|
|
if (!kill(pid, 0)) {
|
2009-01-05 07:11:58 +01:00
|
|
|
syslog(LOG_ERR, "Could not log user %s off line %s.", user, dev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void reread_config(signum)
|
|
|
|
int signum;
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
if (!allow_reread)
|
|
|
|
pending_reread = 1;
|
2020-10-31 10:10:54 +01:00
|
|
|
else {
|
2009-01-05 07:11:58 +01:00
|
|
|
pending_reread = 0;
|
|
|
|
syslog(LOG_NOTICE, "Re-reading configuration file.");
|
2020-10-31 10:10:54 +01:00
|
|
|
while (config[i]) {
|
2009-01-05 07:11:58 +01:00
|
|
|
free(config[i]->times);
|
|
|
|
free(config[i]->ttys);
|
|
|
|
free(config[i]->users);
|
|
|
|
free(config[i]->groups);
|
2020-10-31 10:10:54 +01:00
|
|
|
if (config[i]->messages[IDLEMSG])
|
|
|
|
free(config[i]->messages[IDLEMSG]);
|
|
|
|
if (config[i]->messages[DAYMSG])
|
|
|
|
free(config[i]->messages[DAYMSG]);
|
|
|
|
if (config[i]->messages[SESSMSG])
|
|
|
|
free(config[i]->messages[SESSMSG]);
|
|
|
|
if (config[i]->messages[NOLOGINMSG])
|
|
|
|
free(config[i]->messages[NOLOGINMSG]);
|
2009-01-05 07:11:58 +01:00
|
|
|
free(config[i]);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
read_config();
|
|
|
|
}
|
|
|
|
signal(SIGHUP, reread_config);
|
|
|
|
}
|
|
|
|
|
|
|
|
void reapchild(signum)
|
|
|
|
int signum;
|
|
|
|
{
|
|
|
|
int st;
|
|
|
|
|
|
|
|
wait(&st);
|
|
|
|
signal(SIGCHLD, reapchild);
|
|
|
|
}
|
|
|
|
|
2008-04-02 02:15:25 +02:00
|
|
|
int getdisc(d, host)
|
2009-01-05 07:11:58 +01:00
|
|
|
char *d;
|
2008-04-02 02:15:25 +02:00
|
|
|
char *host;
|
2009-01-05 07:11:58 +01:00
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
int fd;
|
|
|
|
int disc;
|
2009-01-05 07:11:58 +01:00
|
|
|
|
|
|
|
return N_TTY;
|
Remove most platform-specific ifdef workarounds
Since most of the #ifdef hacks are meant to facilitate the use of the
daemon under older versions of SunOS which didn't have many of the utmp
library functions and facilities most modern Unices have, and since they
significantly hamper the readability of the code, they have been
removed. For portabilities sake, further changes will have to be made
anyways, many modern systems, such as newer versions of FreeBSD, don't
support utmp anymore, and require use of utmpx instead. The program will
have to be changed accordingly.
The getdisc() function has been almost entirely stripped, and now is
just a stub that always returns N_TTY. This will have to be changed
quickly, so that the function returns the actual tty discipline, but
works in most cases.
2020-12-16 23:20:09 +01:00
|
|
|
/* TODO: add an actual portable way of getting terminal discipline */
|
2009-01-05 07:11:58 +01:00
|
|
|
}
|
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
int chk_xsession(dev, host) /* returns TIMEOUTD_XSESSION_{REMOTE,LOCAL,NONE} when dev and host seem to be a xSession. */
|
|
|
|
char *dev, *host;
|
2008-04-02 02:15:25 +02:00
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
if (strncmp(host, ":0", 1) == 0) {
|
|
|
|
/* Look here, how we check if it's a Xsession but no telnet or whatever.
|
|
|
|
* The problem is that a xterm running on :0 has the device pts/?. But if we ignore
|
|
|
|
* all pts/?, ssh users won't be restricted.
|
|
|
|
* So, if (tty="pts/?" OR tty=":*") AND host = ":*", we have a Xsession:
|
|
|
|
*
|
|
|
|
* seppy@schleptop:~$ w
|
|
|
|
* 20:06:33 up 18 min, 6 users, load average: 0.14, 0.16, 0.12
|
|
|
|
* USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
|
|
|
|
* dennis :0 - 19:48 ?xdm? 0.00s ? -
|
|
|
|
* dennis pts/1 :0.0 20:00 4:12 0.03s 0.03s bash
|
|
|
|
* dennis pts/2 :0.0 20:01 0.00s 0.18s 0.16s ssh localhost
|
|
|
|
* dennis pts/3 localhost 20:01 0.00s 0.01s 0.00s w
|
|
|
|
*/
|
|
|
|
#ifdef DEBUG
|
|
|
|
syslog(LOG_DEBUG, "LOCAL Xsession detected. device=%s host=%s", dev, host);
|
|
|
|
#endif
|
|
|
|
return TIMEOUTD_XSESSION_LOCAL;
|
|
|
|
} else if (strstr(dev, ":") && strlen(host) > 1 && gethostbyname(host)) {
|
|
|
|
/* What about remote XDMCP sessions?
|
|
|
|
* USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
|
|
|
|
* mark pts/3 mercury Sat11 0.00s 10.99s 0.04s w
|
|
|
|
* rebecca ap:10 ap 10:32 0.00s 0.00s 1.28s x-session-manager
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
syslog(LOG_DEBUG, "REMOTE Xsession detected. device=%s host=%s", dev, host);
|
|
|
|
#endif
|
|
|
|
return TIMEOUTD_XSESSION_REMOTE;
|
|
|
|
} else {
|
|
|
|
#ifdef DEBUG
|
|
|
|
syslog(LOG_DEBUG, "NO xsession detected. device=%s host=%s", dev, host);
|
|
|
|
#endif
|
|
|
|
return TIMEOUTD_XSESSION_NONE;
|
2008-04-02 02:15:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We have to handle Xterms(pts/?) and Xsessions (:0) different:
|
|
|
|
- Check Xsession for idle, but not a XTERM
|
|
|
|
- Send message for pending logoff to X, but not to XTERM
|
|
|
|
-> Don't check XTERM at all
|
|
|
|
- but: check ssh (pts/?) but no XTERM (again)
|
|
|
|
*/
|
2020-10-31 10:10:54 +01:00
|
|
|
int chk_xterm(dev, host) /* returns 1 when dev and host seem to be a xTERM. */
|
|
|
|
char *dev, *host;
|
2008-04-02 02:15:25 +02:00
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
if (strncmp(dev, "pts/0", 3) == 0 && strncmp(host, ":0", 1) == 0) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
syslog(LOG_DEBUG, "XTERM detected. device=%s host=%s Ignoring.", dev, host);
|
|
|
|
#endif
|
|
|
|
return 1;
|
|
|
|
} else
|
|
|
|
return 0;
|
|
|
|
} /* chk_xterm(dev,host) */
|
2008-04-02 02:15:25 +02:00
|
|
|
|
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
void killit_xsession(pid, user, host) /* returns 1 when host seems to be a xSession. */
|
2008-04-02 02:15:25 +02:00
|
|
|
int pid;
|
2009-01-05 07:12:25 +01:00
|
|
|
char *host, *user;
|
2008-04-02 02:15:25 +02:00
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
char msgbuf[512], cmdbuf[1024];
|
|
|
|
/* first, get the message into msgbuf */
|
|
|
|
if (limit_type == NOLOGINMSG) {
|
|
|
|
sprintf(msgbuf, "Logins not allowed at this time. Please try again later.");
|
|
|
|
} else {
|
|
|
|
sprintf(msgbuf, "You have exceeded your %s time limit. Logging you off now.",
|
|
|
|
limit_names[limit_type]);
|
|
|
|
}
|
2008-04-02 02:15:25 +02:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
/* then send the message using xmessage */
|
|
|
|
/* well, this is not really clean: */
|
|
|
|
sprintf(cmdbuf, "su %s -c \"xmessage -display %s -center '%s'&\"", user, host, msgbuf);
|
|
|
|
system(cmdbuf);
|
|
|
|
#ifdef DEBUG
|
|
|
|
syslog(LOG_DEBUG, "cmdbuf=%s", cmdbuf);
|
|
|
|
#endif
|
|
|
|
sleep(KWAIT); /* and give the user some time to read the message ;) */
|
2008-04-02 02:15:25 +02:00
|
|
|
|
2020-10-30 21:56:33 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
#ifndef DEBUG
|
|
|
|
/* kill pid here */
|
|
|
|
kill(pid, SIGTERM); /* otherwise, X crashes */
|
2008-04-02 02:15:25 +02:00
|
|
|
sleep(KWAIT);
|
2020-10-31 10:10:54 +01:00
|
|
|
if (!kill(pid, 0)) { /* SIGHUP might be ignored */
|
|
|
|
kill(pid, SIGKILL); /* then send sure "kill" signal */
|
2008-04-02 02:15:25 +02:00
|
|
|
sleep(KWAIT);
|
2020-10-31 10:10:54 +01:00
|
|
|
if (!kill(pid, 0)) {
|
2009-01-05 07:12:25 +01:00
|
|
|
syslog(LOG_ERR, "Could not log user %s off line %s. (running X)", user, host);
|
2008-04-02 02:15:25 +02:00
|
|
|
}
|
|
|
|
}
|
2020-10-31 10:10:54 +01:00
|
|
|
#else
|
|
|
|
syslog(LOG_ERR, "Would normally logoff user %s running X (kill PID %d)", user, pid);
|
|
|
|
#endif
|
2008-04-02 02:15:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
int chk_ssh(pid) /* seppy; returns true if pid is sshd, otherwise it returns false */
|
2008-04-02 02:15:25 +02:00
|
|
|
pid_t pid;
|
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
sprintf(path, "/proc/%d/stat", pid);
|
|
|
|
proc_file = fopen(path, "r");
|
|
|
|
if (!proc_file) {
|
|
|
|
syslog(LOG_WARNING, "chk_ssh(): PID %d does not exist. Something went wrong. Ignoring.",
|
|
|
|
pid);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
fscanf(proc_file, "%*d (%[^)]", comm);
|
|
|
|
fclose(proc_file);
|
|
|
|
|
|
|
|
if (!strcmp(comm, "sshd"))
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return 0;
|
2020-10-30 21:56:33 +01:00
|
|
|
}
|
2008-04-02 02:15:25 +02:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
char *getusr(pid) /*seppy; returns the name of the user owning process with the Process ID pid */
|
2008-04-02 02:15:25 +02:00
|
|
|
pid_t pid;
|
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
char uid[99];
|
|
|
|
sprintf(path, "/proc/%d/status", pid);
|
|
|
|
proc_file = fopen(path, "r");
|
|
|
|
if (!proc_file) {
|
|
|
|
syslog(LOG_NOTICE, "getusr(): PID %d does not exist. Ignoring.", pid);
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
while (!fscanf(proc_file, "Uid: %s", uid))
|
|
|
|
fgets(uid, 98, proc_file);
|
|
|
|
fclose(proc_file);
|
|
|
|
return getpwuid(atoi(uid))->pw_name;
|
2008-04-02 02:15:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef TIMEOUTDX11
|
2020-10-31 10:10:54 +01:00
|
|
|
Time get_xidle(user, display) /*seppy; returns millicecs since last input event */
|
2008-04-02 02:15:25 +02:00
|
|
|
char *user;
|
|
|
|
char *display;
|
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
Display *dpy;
|
|
|
|
static XScreenSaverInfo *mitInfo = 0;
|
|
|
|
struct passwd *pwEntry;
|
|
|
|
char homedir[50]; /*50 should be enough */
|
|
|
|
char oldhomedir[50];
|
|
|
|
uid_t oldeuid;
|
|
|
|
Time retval = 0;
|
|
|
|
|
|
|
|
pwEntry = getpwnam(user);
|
|
|
|
if (!pwEntry) {
|
|
|
|
syslog(LOG_ERR, "Could not get passwd-entry for user %s", user);
|
|
|
|
}
|
2008-04-02 02:15:25 +02:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2020-10-31 10:10:54 +01:00
|
|
|
syslog(LOG_DEBUG, "su-ing to %s(%d) and connecting to X", user, pwEntry->pw_uid);
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
/*change into the user running x. we need that to connect to X */
|
|
|
|
/*setregid(1000, 1000); We don't need this */
|
|
|
|
|
|
|
|
/*save old, to come back */
|
|
|
|
oldeuid = geteuid();
|
|
|
|
sprintf(oldhomedir, "HOME=%s", getenv("HOME"));
|
|
|
|
|
|
|
|
/*become user */
|
|
|
|
if (seteuid(pwEntry->pw_uid) == -1) {
|
|
|
|
syslog(LOG_ERR, "Could not seteuid(%d).", pwEntry->pw_uid);
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(homedir, "HOME=%s", pwEntry->pw_dir);
|
|
|
|
putenv(homedir);
|
|
|
|
|
|
|
|
/* First, check if there is a xserver.. */
|
|
|
|
if ((dpy = XOpenDisplay(display)) == NULL) { /* = intended */
|
|
|
|
syslog(LOG_NOTICE, "Could not connect to %s to query idle-time for %s. Ignoring.", display,
|
|
|
|
user);
|
|
|
|
} else {
|
|
|
|
if (!mitInfo)
|
|
|
|
mitInfo = XScreenSaverAllocInfo();
|
|
|
|
XScreenSaverQueryInfo(dpy, DefaultRootWindow(dpy), mitInfo);
|
|
|
|
retval = mitInfo->idle;
|
|
|
|
XCloseDisplay(dpy);
|
|
|
|
}
|
|
|
|
/*go back again */
|
|
|
|
putenv(oldhomedir);
|
|
|
|
setuid(oldeuid);
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
} /* get_xidle(user) */
|
2008-04-02 02:15:25 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* seppy; getchild()
|
2020-10-30 21:56:33 +01:00
|
|
|
returns the pid of the first child-process found.
|
|
|
|
- 1 if a error occured,
|
2020-10-31 10:10:54 +01:00
|
|
|
- 0 if none found
|
2020-10-30 21:56:33 +01:00
|
|
|
|
2020-10-31 10:10:54 +01:00
|
|
|
We need this because utmp returns a process owned by
|
|
|
|
root when a user is connected via ssh. If we kill its
|
|
|
|
child (owned by the user) he/she gets logged off */
|
2020-10-30 21:56:33 +01:00
|
|
|
pid_t getcpid(ppid)
|
2008-04-02 02:15:25 +02:00
|
|
|
pid_t ppid;
|
|
|
|
{
|
2020-10-31 10:10:54 +01:00
|
|
|
DIR *proc;
|
|
|
|
FILE *proc_file;
|
|
|
|
struct dirent *cont;
|
|
|
|
char akt_pid[99];
|
|
|
|
char path[512];
|
|
|
|
|
|
|
|
proc = opendir("/proc/");
|
|
|
|
if (proc == NULL) {
|
|
|
|
printf("error opening directory\n");
|
|
|
|
return -1; /* error */
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((cont = readdir(proc)) != NULL) {
|
|
|
|
if (cont->d_type == DT_DIR && isdigit(cont->d_name[0])) { /* check only PIDs */
|
|
|
|
sprintf(path, "/proc/%s/status", cont->d_name);
|
|
|
|
proc_file = fopen(path, "r");
|
|
|
|
if (!proc_file)
|
|
|
|
printf("error opening proc status file %s\n", path);
|
|
|
|
|
|
|
|
while (!fscanf(proc_file, "PPid: %s", akt_pid))
|
|
|
|
fgets(akt_pid, 10, proc_file);
|
|
|
|
|
|
|
|
if (atoi(akt_pid) == ppid)
|
|
|
|
return (pid_t) atoi(cont->d_name); /* return pid of child */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0; /* no child found */
|
|
|
|
} /* getchild(ppid) */
|