Remove unnecessary openlog() and closelog() calls
This commit is contained in:
parent
e6c8f1b6c1
commit
608f4fb896
1 changed files with 0 additions and 124 deletions
124
timeoutd.c
124
timeoutd.c
|
@ -186,9 +186,7 @@ char *argv[];
|
||||||
|
|
||||||
/* The only valid invocations are "timeoutd" or "timeoutd user tty" */
|
/* The only valid invocations are "timeoutd" or "timeoutd user tty" */
|
||||||
if (argc != 1 && argc != 3) {
|
if (argc != 1 && argc != 3) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Incorrect invocation of timeoutd (argc=%d) by UID %d.", argc, getuid());
|
syslog(LOG_ERR, "Incorrect invocation of timeoutd (argc=%d) by UID %d.", argc, getuid());
|
||||||
closelog();
|
|
||||||
exit(5);
|
exit(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,9 +198,7 @@ char *argv[];
|
||||||
* ut_line fields are relative to it.
|
* ut_line fields are relative to it.
|
||||||
*/
|
*/
|
||||||
if (chdir("/dev")) {
|
if (chdir("/dev")) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Could not change working directory to /dev!");
|
syslog(LOG_ERR, "Could not change working directory to /dev!");
|
||||||
closelog();
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,10 +206,8 @@ char *argv[];
|
||||||
/* This is a bit of a shameless hack, but, well, it works. */
|
/* This is a bit of a shameless hack, but, well, it works. */
|
||||||
if (argc == 3) {
|
if (argc == 3) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(SYSLOG_DEBUG, "Running in user check mode. Checking user %s on %s.", argv[1],
|
syslog(SYSLOG_DEBUG, "Running in user check mode. Checking user %s on %s.", argv[1],
|
||||||
argv[2]);
|
argv[2]);
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
strncpy(dev, argv[2], sizeof(dev) - 1);
|
strncpy(dev, argv[2], sizeof(dev) - 1);
|
||||||
dev[sizeof(dev) - 1] = '\0';
|
dev[sizeof(dev) - 1] = '\0';
|
||||||
|
@ -224,11 +218,9 @@ char *argv[];
|
||||||
read_wtmp(); /* Read in today's wtmp entries */
|
read_wtmp(); /* Read in today's wtmp entries */
|
||||||
switch (chk_timeout(argv[1], dev, "", 0, 0)) {
|
switch (chk_timeout(argv[1], dev, "", 0, 0)) {
|
||||||
case DAYMAX:
|
case DAYMAX:
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_NOTICE,
|
syslog(LOG_NOTICE,
|
||||||
"User %s on %s exceeded maximum daily limit (%d minutes). Login check failed.",
|
"User %s on %s exceeded maximum daily limit (%d minutes). Login check failed.",
|
||||||
argv[1], argv[2], config[configline]->daymax);
|
argv[1], argv[2], config[configline]->daymax);
|
||||||
closelog();
|
|
||||||
/*
|
/*
|
||||||
printf("\r\nLogin not permitted. You have exceeded your maximum daily limit.\r\n");
|
printf("\r\nLogin not permitted. You have exceeded your maximum daily limit.\r\n");
|
||||||
printf("Please try again tomorrow.\r\n");
|
printf("Please try again tomorrow.\r\n");
|
||||||
|
@ -236,11 +228,9 @@ char *argv[];
|
||||||
logoff_msg(1);
|
logoff_msg(1);
|
||||||
exit(10);
|
exit(10);
|
||||||
case NOLOGIN:
|
case NOLOGIN:
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_NOTICE,
|
syslog(LOG_NOTICE,
|
||||||
"User %s not allowed to login on %s at this time. Login check failed.", argv[1],
|
"User %s not allowed to login on %s at this time. Login check failed.", argv[1],
|
||||||
argv[2]);
|
argv[2]);
|
||||||
closelog();
|
|
||||||
/*
|
/*
|
||||||
printf("\r\nLogin not permitted at this time. Please try again later.\r\n");
|
printf("\r\nLogin not permitted at this time. Please try again later.\r\n");
|
||||||
*/
|
*/
|
||||||
|
@ -248,18 +238,14 @@ char *argv[];
|
||||||
exit(20);
|
exit(20);
|
||||||
case ACTIVE:
|
case ACTIVE:
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(SYSLOG_DEBUG, "User %s on %s passed login check.", argv[1], argv[2]);
|
syslog(SYSLOG_DEBUG, "User %s on %s passed login check.", argv[1], argv[2]);
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
free_wtmp();
|
free_wtmp();
|
||||||
exit(0);
|
exit(0);
|
||||||
default:
|
default:
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR,
|
syslog(LOG_ERR,
|
||||||
"Internal error checking user %s on %s - unexpected return from chk_timeout",
|
"Internal error checking user %s on %s - unexpected return from chk_timeout",
|
||||||
argv[1], argv[2]);
|
argv[1], argv[2]);
|
||||||
closelog();
|
|
||||||
exit(30);
|
exit(30);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,9 +254,7 @@ char *argv[];
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
if ((pid = fork()) < 0) {
|
if ((pid = fork()) < 0) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Failed to execute fork number 1");
|
syslog(LOG_ERR, "Failed to execute fork number 1");
|
||||||
closelog();
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (pid > 0)
|
if (pid > 0)
|
||||||
|
@ -278,9 +262,7 @@ char *argv[];
|
||||||
|
|
||||||
struct rlimit r;
|
struct rlimit r;
|
||||||
if (getrlimit(RLIMIT_NOFILE, &r) == -1) {
|
if (getrlimit(RLIMIT_NOFILE, &r) == -1) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Coudln't get file resource limit.");
|
syslog(LOG_ERR, "Coudln't get file resource limit.");
|
||||||
closelog();
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
for (int i = r.rlim_cur; i >= 0; --i) {
|
for (int i = r.rlim_cur; i >= 0; --i) {
|
||||||
|
@ -288,16 +270,12 @@ char *argv[];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setsid() < 0) {
|
if (setsid() < 0) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Failed to set new session ID at startup.");
|
syslog(LOG_ERR, "Failed to set new session ID at startup.");
|
||||||
closelog();
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pid = fork()) < 0) {
|
if ((pid = fork()) < 0) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Failed to execute fork number 2");
|
syslog(LOG_ERR, "Failed to execute fork number 2");
|
||||||
closelog();
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (pid > 0)
|
if (pid > 0)
|
||||||
|
@ -305,9 +283,7 @@ char *argv[];
|
||||||
|
|
||||||
umask(0);
|
umask(0);
|
||||||
|
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_NOTICE, "Daemon started.");
|
syslog(LOG_NOTICE, "Daemon started.");
|
||||||
closelog();
|
|
||||||
|
|
||||||
/* the child processes all utmp file entries: */
|
/* the child processes all utmp file entries: */
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -319,9 +295,7 @@ char *argv[];
|
||||||
read_wtmp(); /* Read in today's wtmp entries */
|
read_wtmp(); /* Read in today's wtmp entries */
|
||||||
setutent();
|
setutent();
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(SYSLOG_DEBUG, "Time to check utmp for exceeded limits.");
|
syslog(SYSLOG_DEBUG, "Time to check utmp for exceeded limits.");
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
while ((utmpp = getutent()) != (struct utmp *) NULL)
|
while ((utmpp = getutent()) != (struct utmp *) NULL)
|
||||||
check_idle();
|
check_idle();
|
||||||
|
@ -330,9 +304,7 @@ char *argv[];
|
||||||
if (pending_reread)
|
if (pending_reread)
|
||||||
reread_config(SIGHUP);
|
reread_config(SIGHUP);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(SYSLOG_DEBUG, "Finished checking utmp... sleeping for 1 minute.");
|
syslog(SYSLOG_DEBUG, "Finished checking utmp... sleeping for 1 minute.");
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
sleep(60);
|
sleep(60);
|
||||||
}
|
}
|
||||||
|
@ -348,18 +320,14 @@ void read_wtmp()
|
||||||
struct tm *tm;
|
struct tm *tm;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(SYSLOG_DEBUG, "Reading today's wtmp entries.");
|
syslog(SYSLOG_DEBUG, "Reading today's wtmp entries.");
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((fp = fopen(WTMP_FILE, "r")) == NULL)
|
if ((fp = fopen(WTMP_FILE, "r")) == NULL)
|
||||||
bailout("Could not open wtmp file!", 1);
|
bailout("Could not open wtmp file!", 1);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(SYSLOG_DEBUG, "Seek to end of wtmp");
|
syslog(SYSLOG_DEBUG, "Seek to end of wtmp");
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
/* Go to end of file minus one structure */
|
/* Go to end of file minus one structure */
|
||||||
fseek(fp, -1L * sizeof(struct utmp), SEEK_END);
|
fseek(fp, -1L * sizeof(struct utmp), SEEK_END);
|
||||||
|
@ -392,9 +360,7 @@ void read_wtmp()
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(SYSLOG_DEBUG, "Finished reading today's wtmp entries.");
|
syslog(SYSLOG_DEBUG, "Finished reading today's wtmp entries.");
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,9 +370,7 @@ void free_wtmp()
|
||||||
{
|
{
|
||||||
struct ut_list *ut_list_p;
|
struct ut_list *ut_list_p;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(SYSLOG_DEBUG, "Freeing list of today's wtmp entries.");
|
syslog(SYSLOG_DEBUG, "Freeing list of today's wtmp entries.");
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (wtmplist) {
|
while (wtmplist) {
|
||||||
|
@ -428,9 +392,7 @@ void free_wtmp()
|
||||||
free(ut_list_p);
|
free(ut_list_p);
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(SYSLOG_DEBUG, "Finished freeing list of today's wtmp entries.");
|
syslog(SYSLOG_DEBUG, "Finished freeing list of today's wtmp entries.");
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,11 +420,9 @@ char *time_str;
|
||||||
te->days = 0;
|
te->days = 0;
|
||||||
while (isalpha(*p)) {
|
while (isalpha(*p)) {
|
||||||
if (!p[1] || !isalpha(p[1])) {
|
if (!p[1] || !isalpha(p[1])) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR,
|
syslog(LOG_ERR,
|
||||||
"Malformed day name (%c%c) in time field of config file (%s). Entry ignored.",
|
"Malformed day name (%c%c) in time field of config file (%s). Entry ignored.",
|
||||||
p[0], p[1], CONFIG);
|
p[0], p[1], CONFIG);
|
||||||
closelog();
|
|
||||||
(*t)->days = 0;
|
(*t)->days = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -478,11 +438,9 @@ char *time_str;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (!daynames[i]) {
|
if (!daynames[i]) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR,
|
syslog(LOG_ERR,
|
||||||
"Malformed day name (%c%c) in time field of config file (%s). Entry ignored.",
|
"Malformed day name (%c%c) in time field of config file (%s). Entry ignored.",
|
||||||
p[0], p[1], CONFIG);
|
p[0], p[1], CONFIG);
|
||||||
closelog();
|
|
||||||
(*t)->days = 0;
|
(*t)->days = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -492,11 +450,9 @@ char *time_str;
|
||||||
/* Store start and end times */
|
/* Store start and end times */
|
||||||
if (*p) {
|
if (*p) {
|
||||||
if (strlen(p) != 9 || p[4] != '-') {
|
if (strlen(p) != 9 || p[4] != '-') {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR,
|
syslog(LOG_ERR,
|
||||||
"Malformed time (%s) in time field of config file (%s). Entry ignored.", p,
|
"Malformed time (%s) in time field of config file (%s). Entry ignored.", p,
|
||||||
CONFIG);
|
CONFIG);
|
||||||
closelog();
|
|
||||||
(*t)->days = 0;
|
(*t)->days = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -504,11 +460,9 @@ char *time_str;
|
||||||
te->endtime = atoi(p + 5);
|
te->endtime = atoi(p + 5);
|
||||||
if ((te->starttime == 0 && strncmp(p, "0000-", 5))
|
if ((te->starttime == 0 && strncmp(p, "0000-", 5))
|
||||||
|| (te->endtime == 0 && strcmp(p + 5, "0000"))) {
|
|| (te->endtime == 0 && strcmp(p + 5, "0000"))) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR,
|
syslog(LOG_ERR,
|
||||||
"Invalid range (%s) in time field of config file (%s). Entry ignored.", p,
|
"Invalid range (%s) in time field of config file (%s). Entry ignored.", p,
|
||||||
CONFIG);
|
CONFIG);
|
||||||
closelog();
|
|
||||||
(*t)->days = 0;
|
(*t)->days = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -615,10 +569,8 @@ void read_config()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!config[i]->times || !config[i]->ttys || !config[i]->users || !config[i]->groups) {
|
if (!config[i]->times || !config[i]->ttys || !config[i]->users || !config[i]->groups) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Error on line %d of config file (%s). Line ignored.", linenum,
|
syslog(LOG_ERR, "Error on line %d of config file (%s). Line ignored.", linenum,
|
||||||
CONFIG);
|
CONFIG);
|
||||||
closelog();
|
|
||||||
} else
|
} else
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
@ -783,18 +735,14 @@ char *host;
|
||||||
char cmdbuf[1024];
|
char cmdbuf[1024];
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(SYSLOG_DEBUG, "Warning %s@%s on %s of pending logoff in %d minutes.", user, host, tty,
|
syslog(SYSLOG_DEBUG, "Warning %s@%s on %s of pending logoff in %d minutes.", user, host, tty,
|
||||||
time_remaining);
|
time_remaining);
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (chk_xsession(tty, host)) {
|
if (chk_xsession(tty, host)) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(SYSLOG_DEBUG,
|
syslog(SYSLOG_DEBUG,
|
||||||
"Warning %s running X on %s for pending logout! (%d min%s left)",
|
"Warning %s running X on %s for pending logout! (%d min%s left)",
|
||||||
user, tty, time_remaining, time_remaining == 1 ? "" : "s");
|
user, tty, time_remaining, time_remaining == 1 ? "" : "s");
|
||||||
closelog();
|
|
||||||
|
|
||||||
/* then send the message using xmessage */
|
/* then send the message using xmessage */
|
||||||
/* well, this is not really clean: */
|
/* well, this is not really clean: */
|
||||||
|
@ -804,18 +752,14 @@ char *host;
|
||||||
limit_names[limit_type]);
|
limit_names[limit_type]);
|
||||||
system(cmdbuf);
|
system(cmdbuf);
|
||||||
/*#ifdef DEBUG */
|
/*#ifdef DEBUG */
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_DEBUG, "cmdbuf=%s", cmdbuf);
|
syslog(LOG_DEBUG, "cmdbuf=%s", cmdbuf);
|
||||||
closelog();
|
|
||||||
/*#endif */
|
/*#endif */
|
||||||
sleep(KWAIT); /* and give the user some time to read the message ;) */
|
sleep(KWAIT); /* and give the user some time to read the message ;) */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fd = open(tty, O_WRONLY | O_NOCTTY | O_NONBLOCK)) < 0 || (ttyf = fdopen(fd, "w")) == NULL) {
|
if ((fd = open(tty, O_WRONLY | O_NOCTTY | O_NONBLOCK)) < 0 || (ttyf = fdopen(fd, "w")) == NULL) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Could not open %s to warn of impending logoff.\n", tty);
|
syslog(LOG_ERR, "Could not open %s to warn of impending logoff.\n", tty);
|
||||||
closelog();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fprintf(ttyf,
|
fprintf(ttyf,
|
||||||
|
@ -846,22 +790,16 @@ int session;
|
||||||
|
|
||||||
/* Find primary group for specified user */
|
/* Find primary group for specified user */
|
||||||
if ((pw = getpwnam(user)) == NULL) {
|
if ((pw = getpwnam(user)) == NULL) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Could not get password entry for %s.", user);
|
syslog(LOG_ERR, "Could not get password entry for %s.", user);
|
||||||
closelog();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if ((gr = getgrgid(pw->pw_gid)) == NULL) {
|
if ((gr = getgrgid(pw->pw_gid)) == NULL) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Could not get group name for %s.", user);
|
syslog(LOG_ERR, "Could not get group name for %s.", user);
|
||||||
closelog();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(SYSLOG_DEBUG, "Checking user %s group %s tty %s.", user, gr->gr_name, tty);
|
syslog(SYSLOG_DEBUG, "Checking user %s group %s tty %s.", user, gr->gr_name, tty);
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Check to see if current user matches any entry based on tty/user/group */
|
/* Check to see if current user matches any entry based on tty/user/group */
|
||||||
|
@ -887,14 +825,12 @@ printf("Group %s member %s\n", secgr->gr_name, *p);
|
||||||
if (timematch && ttymatch && usermatch && groupmatch) {
|
if (timematch && ttymatch && usermatch && groupmatch) {
|
||||||
get_day_time(user);
|
get_day_time(user);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(SYSLOG_DEBUG, "Matched entry %d", configline);
|
syslog(SYSLOG_DEBUG, "Matched entry %d", configline);
|
||||||
syslog(SYSLOG_DEBUG,
|
syslog(SYSLOG_DEBUG,
|
||||||
"Idle=%d (max=%d) Sess=%d (max=%d) Daily=%d (max=%d) warntime=%d",
|
"Idle=%d (max=%d) Sess=%d (max=%d) Daily=%d (max=%d) warntime=%d",
|
||||||
idle, config[configline]->idlemax, session,
|
idle, config[configline]->idlemax, session,
|
||||||
config[configline]->sessmax, daytime, config[configline]->daymax,
|
config[configline]->sessmax, daytime, config[configline]->daymax,
|
||||||
config[configline]->warntime);
|
config[configline]->warntime);
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
disc = getdisc(dev, host);
|
disc = getdisc(dev, host);
|
||||||
|
|
||||||
|
@ -968,10 +904,8 @@ void check_idle()
|
||||||
|
|
||||||
if (aktconfigline > 0) { /* > 0 if user is not in config */
|
if (aktconfigline > 0) { /* > 0 if user is not in config */
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(SYSLOG_DEBUG, "User %s or * not in config -> No restrictions. Not checking %s on %s",
|
syslog(SYSLOG_DEBUG, "User %s or * not in config -> No restrictions. Not checking %s on %s",
|
||||||
user, user, dev);
|
user, user, dev);
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
return; /* now, we return because the user beeing checked is not in config, so he has no restrictions */
|
return; /* now, we return because the user beeing checked is not in config, so he has no restrictions */
|
||||||
}
|
}
|
||||||
|
@ -995,10 +929,8 @@ void check_idle()
|
||||||
#ifdef TIMEOUTDX11
|
#ifdef TIMEOUTDX11
|
||||||
if (chk_xsession(dev, host) && !chk_xterm(dev, host)) { /* check idle for Xsession, but not for xterm */
|
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 */
|
idle = get_xidle(user, host) / 1000 / 60; /* get_xidle returns millisecs, we need mins */
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(SYSLOG_DEBUG, "get_xidle(%s,%s) returned %d mins idle for %s.", dev, host,
|
syslog(SYSLOG_DEBUG, "get_xidle(%s,%s) returned %d mins idle for %s.", dev, host,
|
||||||
(int) idle, user);
|
(int) idle, user);
|
||||||
closelog();
|
|
||||||
} else if (chk_xterm(dev, host))
|
} else if (chk_xterm(dev, host))
|
||||||
return;
|
return;
|
||||||
else
|
else
|
||||||
|
@ -1009,50 +941,38 @@ void check_idle()
|
||||||
switch (chk_timeout(user, dev, host, idle, sesstime)) {
|
switch (chk_timeout(user, dev, host, idle, sesstime)) {
|
||||||
case ACTIVE:
|
case ACTIVE:
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(SYSLOG_DEBUG, "User %s is active.", user);
|
syslog(SYSLOG_DEBUG, "User %s is active.", user);
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case IDLEMAX:
|
case IDLEMAX:
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_NOTICE,
|
syslog(LOG_NOTICE,
|
||||||
"User %s exceeded idle limit (idle for %ld minutes, max=%d).\n",
|
"User %s exceeded idle limit (idle for %ld minutes, max=%d).\n",
|
||||||
user, idle, config[configline]->idlemax);
|
user, idle, config[configline]->idlemax);
|
||||||
closelog();
|
|
||||||
killit(utmpp->ut_pid, user, dev, host);
|
killit(utmpp->ut_pid, user, dev, host);
|
||||||
break;
|
break;
|
||||||
case SESSMAX:
|
case SESSMAX:
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_NOTICE,
|
syslog(LOG_NOTICE,
|
||||||
"User %s exceeded maximum session limit at %s (on for %ld minutes, max=%d).\n",
|
"User %s exceeded maximum session limit at %s (on for %ld minutes, max=%d).\n",
|
||||||
user, dev, sesstime, config[configline]->sessmax);
|
user, dev, sesstime, config[configline]->sessmax);
|
||||||
closelog();
|
|
||||||
killit(utmpp->ut_pid, user, dev, host);
|
killit(utmpp->ut_pid, user, dev, host);
|
||||||
break;
|
break;
|
||||||
case DAYMAX:
|
case DAYMAX:
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_NOTICE,
|
syslog(LOG_NOTICE,
|
||||||
"User %s exceeded maximum daily limit (on for %d minutes, max=%d).\n",
|
"User %s exceeded maximum daily limit (on for %d minutes, max=%d).\n",
|
||||||
user, daytime, config[configline]->daymax);
|
user, daytime, config[configline]->daymax);
|
||||||
closelog();
|
|
||||||
killit(utmpp->ut_pid, user, dev, host);
|
killit(utmpp->ut_pid, user, dev, host);
|
||||||
break;
|
break;
|
||||||
case NOLOGIN:
|
case NOLOGIN:
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
syslog(LOG_NOTICE, "NOLOGIN period reached for user %s@%s. (pid %d)", user, host,
|
syslog(LOG_NOTICE, "NOLOGIN period reached for user %s@%s. (pid %d)", user, host,
|
||||||
utmpp->ut_pid);
|
utmpp->ut_pid);
|
||||||
#else
|
#else
|
||||||
syslog(LOG_NOTICE, "NOLOGIN period reached for user %s %s", user, host);
|
syslog(LOG_NOTICE, "NOLOGIN period reached for user %s %s", user, host);
|
||||||
#endif
|
#endif
|
||||||
closelog();
|
|
||||||
killit(utmpp->ut_pid, user, dev, host);
|
killit(utmpp->ut_pid, user, dev, host);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Internal error - unexpected return from chk_timeout");
|
syslog(LOG_ERR, "Internal error - unexpected return from chk_timeout");
|
||||||
closelog();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1060,27 +980,21 @@ void bailout(message, status) /* display error message and exit */
|
||||||
int status; /* exit status */
|
int status; /* exit status */
|
||||||
char *message; /* pointer to the error message */
|
char *message; /* pointer to the error message */
|
||||||
{
|
{
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Exiting - %s", message);
|
syslog(LOG_ERR, "Exiting - %s", message);
|
||||||
closelog();
|
|
||||||
exit(status);
|
exit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
void shut_down(signum)
|
void shut_down(signum)
|
||||||
int signum;
|
int signum;
|
||||||
{
|
{
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_NOTICE, "Received SIGTERM.. exiting.");
|
syslog(LOG_NOTICE, "Received SIGTERM.. exiting.");
|
||||||
closelog();
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void segfault(signum)
|
void segfault(signum)
|
||||||
int signum;
|
int signum;
|
||||||
{
|
{
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_NOTICE, "Received SIGSEGV.. Something went wrong! Exiting!");
|
syslog(LOG_NOTICE, "Received SIGSEGV.. Something went wrong! Exiting!");
|
||||||
closelog();
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1129,9 +1043,7 @@ char *host;
|
||||||
}
|
}
|
||||||
/* Tell user which limit they have exceeded and that they will be logged off */
|
/* Tell user which limit they have exceeded and that they will be logged off */
|
||||||
if ((tty = open(dev, O_WRONLY | O_NOCTTY | O_NONBLOCK)) < 0) {
|
if ((tty = open(dev, O_WRONLY | O_NOCTTY | O_NONBLOCK)) < 0) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Could not write logoff message to %s.", dev);
|
syslog(LOG_ERR, "Could not write logoff message to %s.", dev);
|
||||||
closelog();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1141,18 +1053,14 @@ char *host;
|
||||||
(because we don't want to slay another user ;) */
|
(because we don't want to slay another user ;) */
|
||||||
cpid = getcpid(pid);
|
cpid = getcpid(pid);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_NOTICE, "I am at killit() pid=%d user=%s child=%d line %d", pid, user, cpid,
|
syslog(LOG_NOTICE, "I am at killit() pid=%d user=%s child=%d line %d", pid, user, cpid,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (chk_ssh(pid) && chk_ssh(cpid) && !strcmp(getusr(cpid), user)) {
|
if (chk_ssh(pid) && chk_ssh(cpid) && !strcmp(getusr(cpid), user)) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_NOTICE, "User %s (pid:%d, cpid:%d) logged in via ssh from %s.", user, pid, cpid,
|
syslog(LOG_NOTICE, "User %s (pid:%d, cpid:%d) logged in via ssh from %s.", user, pid, cpid,
|
||||||
host);
|
host);
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
pid = cpid;
|
pid = cpid;
|
||||||
}
|
}
|
||||||
|
@ -1162,9 +1070,7 @@ char *host;
|
||||||
close(tty);
|
close(tty);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_NOTICE, "Would normally kill pid %d user %s on %s", pid, user, dev);
|
syslog(LOG_NOTICE, "Would normally kill pid %d user %s on %s", pid, user, dev);
|
||||||
closelog();
|
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1178,9 +1084,7 @@ char *host;
|
||||||
kill(pid, SIGKILL); /* then send sure "kill" signal */
|
kill(pid, SIGKILL); /* then send sure "kill" signal */
|
||||||
sleep(KWAIT);
|
sleep(KWAIT);
|
||||||
if (!kill(pid, 0)) {
|
if (!kill(pid, 0)) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Could not log user %s off line %s.", user, dev);
|
syslog(LOG_ERR, "Could not log user %s off line %s.", user, dev);
|
||||||
closelog();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exit(0);
|
exit(0);
|
||||||
|
@ -1195,9 +1099,7 @@ int signum;
|
||||||
pending_reread = 1;
|
pending_reread = 1;
|
||||||
else {
|
else {
|
||||||
pending_reread = 0;
|
pending_reread = 0;
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_NOTICE, "Re-reading configuration file.");
|
syslog(LOG_NOTICE, "Re-reading configuration file.");
|
||||||
closelog();
|
|
||||||
while (config[i]) {
|
while (config[i]) {
|
||||||
free(config[i]->times);
|
free(config[i]->times);
|
||||||
free(config[i]->ttys);
|
free(config[i]->ttys);
|
||||||
|
@ -1257,9 +1159,7 @@ char *dev, *host;
|
||||||
* dennis pts/3 localhost 20:01 0.00s 0.01s 0.00s w
|
* dennis pts/3 localhost 20:01 0.00s 0.01s 0.00s w
|
||||||
*/
|
*/
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_DEBUG, "LOCAL Xsession detected. device=%s host=%s", dev, host);
|
syslog(LOG_DEBUG, "LOCAL Xsession detected. device=%s host=%s", dev, host);
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
return TIMEOUTD_XSESSION_LOCAL;
|
return TIMEOUTD_XSESSION_LOCAL;
|
||||||
} else if (strstr(dev, ":") && strlen(host) > 1 && gethostbyname(host)) {
|
} else if (strstr(dev, ":") && strlen(host) > 1 && gethostbyname(host)) {
|
||||||
|
@ -1270,16 +1170,12 @@ char *dev, *host;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_DEBUG, "REMOTE Xsession detected. device=%s host=%s", dev, host);
|
syslog(LOG_DEBUG, "REMOTE Xsession detected. device=%s host=%s", dev, host);
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
return TIMEOUTD_XSESSION_REMOTE;
|
return TIMEOUTD_XSESSION_REMOTE;
|
||||||
} else {
|
} else {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_DEBUG, "NO xsession detected. device=%s host=%s", dev, host);
|
syslog(LOG_DEBUG, "NO xsession detected. device=%s host=%s", dev, host);
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
return TIMEOUTD_XSESSION_NONE;
|
return TIMEOUTD_XSESSION_NONE;
|
||||||
}
|
}
|
||||||
|
@ -1296,9 +1192,7 @@ char *dev, *host;
|
||||||
{
|
{
|
||||||
if (strncmp(dev, "pts/0", 3) == 0 && strncmp(host, ":0", 1) == 0) {
|
if (strncmp(dev, "pts/0", 3) == 0 && strncmp(host, ":0", 1) == 0) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_DEBUG, "XTERM detected. device=%s host=%s Ignoring.", dev, host);
|
syslog(LOG_DEBUG, "XTERM detected. device=%s host=%s Ignoring.", dev, host);
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
} else
|
} else
|
||||||
|
@ -1324,9 +1218,7 @@ char *host, *user;
|
||||||
sprintf(cmdbuf, "su %s -c \"xmessage -display %s -center '%s'&\"", user, host, msgbuf);
|
sprintf(cmdbuf, "su %s -c \"xmessage -display %s -center '%s'&\"", user, host, msgbuf);
|
||||||
system(cmdbuf);
|
system(cmdbuf);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_DEBUG, "cmdbuf=%s", cmdbuf);
|
syslog(LOG_DEBUG, "cmdbuf=%s", cmdbuf);
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
sleep(KWAIT); /* and give the user some time to read the message ;) */
|
sleep(KWAIT); /* and give the user some time to read the message ;) */
|
||||||
|
|
||||||
|
@ -1339,15 +1231,11 @@ char *host, *user;
|
||||||
kill(pid, SIGKILL); /* then send sure "kill" signal */
|
kill(pid, SIGKILL); /* then send sure "kill" signal */
|
||||||
sleep(KWAIT);
|
sleep(KWAIT);
|
||||||
if (!kill(pid, 0)) {
|
if (!kill(pid, 0)) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Could not log user %s off line %s. (running X)", user, host);
|
syslog(LOG_ERR, "Could not log user %s off line %s. (running X)", user, host);
|
||||||
closelog();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Would normally logoff user %s running X (kill PID %d)", user, pid);
|
syslog(LOG_ERR, "Would normally logoff user %s running X (kill PID %d)", user, pid);
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1359,10 +1247,8 @@ pid_t pid;
|
||||||
sprintf(path, "/proc/%d/stat", pid);
|
sprintf(path, "/proc/%d/stat", pid);
|
||||||
proc_file = fopen(path, "r");
|
proc_file = fopen(path, "r");
|
||||||
if (!proc_file) {
|
if (!proc_file) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_WARNING, "chk_ssh(): PID %d does not exist. Something went wrong. Ignoring.",
|
syslog(LOG_WARNING, "chk_ssh(): PID %d does not exist. Something went wrong. Ignoring.",
|
||||||
pid);
|
pid);
|
||||||
closelog();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1382,9 +1268,7 @@ pid_t pid;
|
||||||
sprintf(path, "/proc/%d/status", pid);
|
sprintf(path, "/proc/%d/status", pid);
|
||||||
proc_file = fopen(path, "r");
|
proc_file = fopen(path, "r");
|
||||||
if (!proc_file) {
|
if (!proc_file) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_NOTICE, "getusr(): PID %d does not exist. Ignoring.", pid);
|
syslog(LOG_NOTICE, "getusr(): PID %d does not exist. Ignoring.", pid);
|
||||||
closelog();
|
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
while (!fscanf(proc_file, "Uid: %s", uid))
|
while (!fscanf(proc_file, "Uid: %s", uid))
|
||||||
|
@ -1408,15 +1292,11 @@ char *display;
|
||||||
|
|
||||||
pwEntry = getpwnam(user);
|
pwEntry = getpwnam(user);
|
||||||
if (!pwEntry) {
|
if (!pwEntry) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Could not get passwd-entry for user %s", user);
|
syslog(LOG_ERR, "Could not get passwd-entry for user %s", user);
|
||||||
closelog();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_DEBUG, "su-ing to %s(%d) and connecting to X", user, pwEntry->pw_uid);
|
syslog(LOG_DEBUG, "su-ing to %s(%d) and connecting to X", user, pwEntry->pw_uid);
|
||||||
closelog();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*change into the user running x. we need that to connect to X */
|
/*change into the user running x. we need that to connect to X */
|
||||||
|
@ -1428,9 +1308,7 @@ char *display;
|
||||||
|
|
||||||
/*become user */
|
/*become user */
|
||||||
if (seteuid(pwEntry->pw_uid) == -1) {
|
if (seteuid(pwEntry->pw_uid) == -1) {
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_ERR, "Could not seteuid(%d).", pwEntry->pw_uid);
|
syslog(LOG_ERR, "Could not seteuid(%d).", pwEntry->pw_uid);
|
||||||
closelog();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(homedir, "HOME=%s", pwEntry->pw_dir);
|
sprintf(homedir, "HOME=%s", pwEntry->pw_dir);
|
||||||
|
@ -1438,10 +1316,8 @@ char *display;
|
||||||
|
|
||||||
/* First, check if there is a xserver.. */
|
/* First, check if there is a xserver.. */
|
||||||
if ((dpy = XOpenDisplay(display)) == NULL) { /* = intended */
|
if ((dpy = XOpenDisplay(display)) == NULL) { /* = intended */
|
||||||
openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON);
|
|
||||||
syslog(LOG_NOTICE, "Could not connect to %s to query idle-time for %s. Ignoring.", display,
|
syslog(LOG_NOTICE, "Could not connect to %s to query idle-time for %s. Ignoring.", display,
|
||||||
user);
|
user);
|
||||||
closelog();
|
|
||||||
} else {
|
} else {
|
||||||
if (!mitInfo)
|
if (!mitInfo)
|
||||||
mitInfo = XScreenSaverAllocInfo();
|
mitInfo = XScreenSaverAllocInfo();
|
||||||
|
|
Loading…
Add table
Reference in a new issue