--- timeoutd-1.5.orig/Makefile +++ timeoutd-1.5/Makefile @@ -1,6 +1,9 @@ -CFLAGS=-fomit-frame-pointer -m486 -O2 -s +CFLAGS=-fomit-frame-pointer -O2 -s -g -Wall timeoutd: timeoutd.c Makefile - $(CC) $(CFLAGS) -o timeoutd timeoutd.c + #$(CC) $(CFLAGS) -o timeoutd timeoutd.c + $(CC) $(CFLAGS) -o timeoutd.o -c timeoutd.c -DTIMEOUTDX11 + $(CC) $(CFLAGS) -o timeoutd -L/usr/X11R6/lib timeoutd.o -lXss -lXext + install: install -o root -g system -m 2111 timeoutd /usr/etc/timeoutd --- timeoutd-1.5.orig/README +++ timeoutd-1.5/README @@ -1,4 +1,4 @@ -TIMEOUTD 1.4 by Shane Alderton +TIMEOUTD 1.5 by Shane Alderton Timeoutd is a programme which allows you to control the following characteristics on a user by user and/or group by group basis for @@ -41,4 +41,4 @@ Please sends bugs, comments, suggestions to: -shane@ion.apana.org.au (Shane Alderton) +shanea@bigpond.net.au (Shane Alderton) --- timeoutd-1.5.orig/timeoutd.8 +++ timeoutd-1.5/timeoutd.8 @@ -2,11 +2,13 @@ .SH NAME timeoutd \- Enforce idle and session time restrictions .SH SYNOPSIS -.B /usr/etc/timeoutd [ user tty ] +.B /usr/sbin/timeoutd [ user tty ] .SH DESCRIPTION -.I timeoutd enforces the time restrictions specified in /usr/etc/timeouts. +.B timeoutd +enforces the time restrictions specified in +.IR /etc/timeouts . When invoked in daemon mode (without any parameters) timeoutd backgrounds -itself, then scans \fB/etc/utmp\fR every minute and checks /usr/etc/timeouts +itself, then scans \fB/var/run/utmp\fR every minute and checks \fB/etc/timeouts\fR for an entry which matches that user, based on: .IP "\- The current day and time" .IP "\- The tty that the user is currently logged in on" @@ -14,12 +16,19 @@ .IP "\- Any primary or secondary groups the user is in" .PP If a match is found, the limits specified for that entry are enforced by -sending a SIGHUP (Hangup signal) to the user's login process, followed -after 5 seconds by a SIGKILL (Sure kill signal) to ensure the user is +sending a +.B SIGHUP +(Hangup signal) to the user's login process, followed +after 5 seconds by a +.B SIGKILL +(Sure kill signal) to ensure the user is logged out. .PP -Where possible, timeoutd will send a warning to the user -every minute for 5 minutes (or other time specified in /usr/etc/timeouts) +Where possible, +.B timeoutd +will send a warning to the user +every minute for 5 minutes (or other time specified in +.IR /etc/timeouts ) before logging them out. Warnings are not sent for exceeded idle limits, as this would count as activity on the terminal. .PP @@ -28,19 +37,24 @@ .PP When calculating idle time, any activity on the terminal, either incoming (such as typing) or outgoing (such as information displayed on the screen) -is counted as activity. This is to prevent logoffs during file transfers. +is counted as activity. This is to prevent log-offs during file transfers. .PP -Under Linux, timeoutd detects when a serial line is in SLIP mode and disables +Under Linux, +.B timeoutd +detects when a serial line is in SLIP mode and disables idle time limit checking (as the last read/write times for the tty are not updated). .PP Debug information, error messages and notification of users who have been timed out are all recorded via syslog (facility=DAEMON). .PP -Timeoutd can also be invoked by login to check whether a user is allowed +.B timeoutd +can also be invoked by login to check whether a user is allowed to login at that time, or whether they have exceeded their daily time limit. When invoked in this way, by passing a username and tty (without the leading -/dev) on the command line, timeoutd returns one of the following exit codes: +/dev) on the command line, +.B timeoutd +returns one of the following exit codes: .IP "0 User is allowed to login .IP "1 Fatal error .IP "5 Incorrect command line format @@ -48,9 +62,9 @@ .IP "20 User not permitted to login at this time on this tty .IP "30 Internal error checking user name (probably invalid user name) .SH FILES -.IP "/usr/etc/timeouts \- lists valid login times and idle/session time restrictions -.IP "/etc/utmp \- current login sessions -.IP "/usr/adm/wtmp \- for calculating total logged in time for current day +.IP "/etc/timeouts \- lists valid login times and idle/session time restrictions +.IP "/var/run/utmp \- current login sessions +.IP "/var/log/wtmp \- for calculating total logged in time for current day .SH BUGS Sessions which end in the current day but started before midnight will not be considered when calculating total daily logged in time for a @@ -61,4 +75,5 @@ .SH "SEE ALSO" .BR timeouts "(5) .SH "WRITTEN BY" -Shane Alderton +Orginally written by Shane Alderton , updated by +Dennis Stampfer . --- timeoutd-1.5.orig/timeoutd.c +++ timeoutd-1.5/timeoutd.c @@ -22,11 +22,16 @@ programme upon which this programme was based. */ +/*#define DEBUG _DEBUG_ */ +#include +#include +#include #include #include #include #include #include +#include #include #include #include @@ -36,6 +41,12 @@ #include #include #include +#include + +#ifdef TIMEOUTDX11 +#include +#include +#endif #define OPENLOG_FLAGS LOG_CONS|LOG_PID #define SYSLOG_DEBUG LOG_DEBUG @@ -80,7 +91,7 @@ while (fread(&uent, sizeof(struct utmp), 1, utfile) == 1) { - if (uent.ut_line[0] != 0 && uent.ut_name[0] != 0) + if (uent.ut_line[0] != 0 && uent.ut_name[0] != 0) return &uent; } return (struct utmp *) NULL; @@ -93,7 +104,7 @@ #endif #ifndef CONFIG -#define CONFIG "/usr/etc/timeouts" +#define CONFIG "/etc/timeouts" #endif #define MAXLINES 512 @@ -104,6 +115,7 @@ #define SESSMAX 3 #define DAYMAX 4 #define NOLOGIN 5 +/*#define XSESSION 6*/ #define IDLEMSG 0 #define SESSMSG 1 #define DAYMSG 2 @@ -120,13 +132,30 @@ char *ctime(); /* returns pointer to time string */ struct utmp *getutent(); /* returns next utmp file entry */ void shutdown(); +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 */ + +#ifdef TIMEOUTDX11 +Time get_xidle(); /* seppy: how long is user idle? (user,display)*/ +#endif + struct ut_list { struct utmp elem; @@ -157,8 +186,8 @@ struct config_ent *config[MAXLINES + 1]; char errmsg[256]; -char dev[24]; -char limit_type; +char dev[sizeof(utmpp->ut_line)]; +unsigned char limit_type; int configline = 0; int pending_reread = 0; int allow_reread = 0; @@ -166,6 +195,9 @@ 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*/ #ifdef NEED_STRCASECMP int strcasecmp(char *s1, char *s2) @@ -216,7 +248,7 @@ } #endif -main(argc, argv) +int main(argc, argv) int argc; char *argv[]; { @@ -225,6 +257,7 @@ signal(SIGCHLD, reapchild); signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); + signal(SIGSEGV, segfault); openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); @@ -240,15 +273,29 @@ /* read config file into memory */ read_config(); +/* 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. + */ + if (chdir("/dev")) + { + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(LOG_ERR, "Could not change working directory to /dev!"); + closelog(); + exit(1); + } + /* Handle the "timeoutd user tty" invocation */ /* This is a bit of a shameless hack, but, well, it works. */ if (argc == 3) { +#ifdef DEBUG openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); syslog(SYSLOG_DEBUG, "Running in user check mode. Checking user %s on %s.", argv[1], argv[2]); closelog(); - strcpy(dev, "/dev/"); - strcat(dev, argv[2]); +#endif + strncpy(dev, argv[2], sizeof(dev) - 1); + dev[sizeof(dev) - 1] = '\0'; time_now = time((time_t *)0); /* get current time */ now = *(localtime(&time_now)); /* Break it into bits */ now_hhmm = now.tm_hour * 100 + now.tm_min; @@ -280,10 +327,12 @@ logoff_msg(1); exit(20); case ACTIVE: +#ifdef DEBUG openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); syslog(SYSLOG_DEBUG, "User %s on %s passed login check.", argv[1], argv[2]); - free_wtmp(); closelog(); +#endif + free_wtmp(); exit(0); default: openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); @@ -317,18 +366,22 @@ allow_reread = 0; read_wtmp(); /* Read in today's wtmp entries */ setutent(); +#ifdef DEBUG openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); syslog(SYSLOG_DEBUG, "Time to check utmp for exceeded limits."); closelog(); +#endif while ((utmpp = getutent()) != (struct utmp *) NULL) check_idle(); free_wtmp(); /* Free up memory used by today's wtmp entries */ allow_reread = 1; if (pending_reread) reread_config(SIGHUP); +#ifdef DEBUG openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); syslog(SYSLOG_DEBUG, "Finished checking utmp... sleeping for 1 minute."); closelog(); +#endif sleep(60); } } @@ -340,18 +393,21 @@ FILE *fp; struct utmp ut; struct tm *tm; - char user[9]; +#ifdef DEBUG openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); syslog(SYSLOG_DEBUG, "Reading today's wtmp entries."); closelog(); +#endif if ((fp = fopen(WTMP_FILE, "r")) == NULL) bailout("Could not open wtmp file!", 1); +#ifdef DEBUG openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); syslog(SYSLOG_DEBUG, "Seek to end of wtmp"); closelog(); +#endif /* Go to end of file minus one structure */ fseek(fp, -1L * sizeof(struct utmp), SEEK_END); @@ -381,18 +437,22 @@ if (fseek(fp, -2 * sizeof(struct utmp), SEEK_CUR) < 0) break; } fclose(fp); +#ifdef DEBUG openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); syslog(SYSLOG_DEBUG, "Finished reading today's wtmp entries."); closelog(); +#endif } /* Free up memory used by today's wtmp entries */ void free_wtmp() { +#ifdef DEBUG openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); syslog(SYSLOG_DEBUG, "Freeing list of today's wtmp entries."); closelog(); +#endif while (wtmplist) { @@ -413,9 +473,11 @@ wtmplist = wtmplist->next; free(ut_list_p); } +#ifdef DEBUG openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); syslog(SYSLOG_DEBUG, "Finished freeing list of today's wtmp entries."); closelog(); +#endif } void store_times(t, time_str) @@ -488,7 +550,7 @@ } te->starttime = atoi(p); te->endtime = atoi(p+5); - if (te->starttime == 0 && strncmp(p, "0000-", 5) || te->endtime == 0 && strcmp(p+5, "0000")) + if ((te->starttime == 0 && strncmp(p, "0000-", 5)) || (te->endtime == 0 && strcmp(p+5, "0000"))) { openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); syslog(LOG_ERR, "Invalid range (%s) in time field of config file (%s). Entry ignored.", p, CONFIG); @@ -517,13 +579,15 @@ else strcpy(*a, b); } -read_config() +void read_config() { FILE *config_file; char *p; char *lstart; int i = 0; +#ifdef DEBUG int j = 0; +#endif char line[256]; char *tok; int linenum = 0; @@ -578,17 +642,17 @@ if (tok != NULL) { config[i]->idlemax = atoi(tok); - if (p = strchr(tok, ';')) alloc_cp(&config[i]->messages[IDLEMSG], p+1); + 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, ';')) alloc_cp(&config[i]->messages[SESSMSG], p+1); + 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, ';')) alloc_cp(&config[i]->messages[DAYMSG], p+1); + if ((p = strchr(tok, ';')) != NULL) alloc_cp(&config[i]->messages[DAYMSG], p+1); } if ((tok = strsep(&lstart, ":")) != NULL) { @@ -646,13 +710,13 @@ while (te->days) { if (daynums[now.tm_wday] & te->days && /* Date within range */ - (te->starttime <= te->endtime && /* Time within range */ + ((te->starttime <= te->endtime && /* Time within range */ now_hhmm >= te->starttime && - now_hhmm <= te->endtime + now_hhmm <= te->endtime) || - te->starttime > te->endtime && + (te->starttime > te->endtime && (now_hhmm >= te->starttime || - now_hhmm <= te->endtime) + now_hhmm <= te->endtime)) ) ) return 1; @@ -666,7 +730,6 @@ char *in_set; { char *t; - char *q; char *set = (char *) malloc(strlen(in_set) + 1); if (set == NULL) bailout("Out of memory", 1); @@ -771,18 +834,43 @@ return; } -void warnpending(tty, time_remaining) +void warnpending(tty, time_remaining, user, host) char *tty; int time_remaining; +char *user; +char *host; { + int fd; FILE *ttyf; - FILE *msgfile = NULL; + char cmdbuf[1024]; +#ifdef DEBUG openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); - syslog(SYSLOG_DEBUG, "Warning user on %s of pending logoff in %d minutes.", - tty, time_remaining); + syslog(SYSLOG_DEBUG, "Warning %s@%s on %s of pending logoff in %d minutes.", + user, host, tty, time_remaining); closelog(); - if ((ttyf = fopen(tty, "w")) == NULL) +#endif + + if(chk_xsession(tty, host)) { + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(SYSLOG_DEBUG, "Warning %s running X on %s for pending logout! (%d min%s left)", user, tty, time_remaining, time_remaining==1?"":"s"); + closelog(); + + /* 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, tty, time_remaining, time_remaining==1?"":"s", limit_names[limit_type]); + system(cmdbuf); + /*#ifdef DEBUG*/ + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(LOG_DEBUG, "cmdbuf=%s", cmdbuf); + closelog(); + /*#endif*/ + sleep(KWAIT); /* and give the user some time to read the message ;) */ + return; + } + + 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); @@ -808,7 +896,7 @@ char ttymatch = 0; char usermatch = 0; char groupmatch = 0; - char *tty = dev + 5; /* Skip over the /dev/ */ + char *tty = dev; char **p; int disc; @@ -830,9 +918,11 @@ return 0; } +#ifdef DEBUG openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); syslog(SYSLOG_DEBUG, "Checking user %s group %s tty %s.", user, gr->gr_name, tty); closelog(); +#endif /* Check to see if current user matches any entry based on tty/user/group */ while (config[configline]) @@ -866,11 +956,13 @@ if (timematch && ttymatch && usermatch && groupmatch) { get_day_time(user); +#ifdef DEBUG openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); 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); closelog(); - disc = getdisc(dev); +#endif + disc = getdisc(dev, host); limit_type = NOLOGINMSG; if (!config[configline]->login_allowed) @@ -891,12 +983,12 @@ /* If none of those have been exceeded, then warn users of upcoming logouts */ limit_type = DAYMSG; if (config[configline]->daymax > 0 && daytime >= config[configline]->daymax - config[configline]->warntime) - warnpending(dev, config[configline]->daymax - daytime); + 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); + warnpending(dev, config[configline]->sessmax - session, user, host); } /* Otherwise, leave the poor net addict alone */ @@ -909,25 +1001,49 @@ return ACTIVE; } -check_idle() /* Check for exceeded time limits & logoff exceeders */ +void check_idle() /* Check for exceeded time limits & logoff exceeders */ { - char user[12]; - char host[17]; + char user[sizeof(utmpp->ut_user)]; + char host[sizeof(utmpp->ut_host)]; struct stat status, *pstat; - time_t idle, start, sesstime, time(); + time_t idle, sesstime, time(); + short aktconfigline = -1; /* -1 if user is in config; >0 if he's not in config, * is handled in an other way */ pstat = &status; /* point to status structure */ #ifndef SUNOS if (utmpp->ut_type != USER_PROCESS || !utmpp->ut_user[0]) /* if not user process */ - return(0); /* skip the utmp entry */ + return; /* skip the utmp entry */ +#endif + strncpy(user, utmpp->ut_user, sizeof(user) - 1); /* get user name */ + user[sizeof(user) - 1] = '\0'; /* null terminate user name string */ + + + /* Only check user if he is mentioned in the config */ + + if(!config[0]) + return; /* no entries in config */ + while(config[++aktconfigline] && aktconfigline >= 0) + if(strcmp(config[aktconfigline]->users, user) == 0 || config[aktconfigline]->users[0] == '*') { + aktconfigline = -2; /* we found user or * in config, so he/they has/have restrictions */ + break; + } + + if(aktconfigline > 0) { /* > 0 if user is in config */ +#ifdef DEBUG + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(SYSLOG_DEBUG, "User %s or * not in config -> No restrictions. Not checking %s on %s", user, user, dev); + closelog(); #endif - strncpy(user, utmpp->ut_user, 8); /* get user name */ - user[8] = '\0'; /* null terminate user name string */ - strncpy(host, utmpp->ut_host, 16); /* get host name */ - host[16] = '\0'; - strcpy(dev, "/dev/"); /* add "/dev/" directory prefix */ - strcat(dev, utmpp->ut_line); /* append basename of port */ - if (stat(dev, pstat)) /* if can't get status for port */ + return; /* now, we return because the user beeing checked is not in config, so he has no restrictions */ + } + + + strncpy(host, utmpp->ut_host, sizeof(host) - 1); /* get host name */ + host[sizeof(host) - 1] = '\0'; + strncpy(dev, utmpp->ut_line, sizeof(dev) - 1); /* get device name */ + dev[sizeof(dev) - 1] = '\0'; + if (stat(dev, pstat) && !chk_xsession(dev, host)) /* if can't get status for + port && if it's no Xsession*/ { sprintf(errmsg, "Can't get status of user %s's terminal (%s)\n", user, dev); @@ -937,7 +1053,18 @@ * current time less last access time OR * current time less last modified time */ - idle = (time_now - max(pstat->st_atime, pstat->st_mtime)) / 60; +#ifdef TIMEOUTDX11 + if(chk_xsession(dev, host) && !chk_xterm(dev, host)) { /* check idle for Session, but not for xterm */ + idle = get_xidle(user, dev) / 1000 / 60; /* get_xidle returns millisecs, we need mins */ + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(SYSLOG_DEBUG, "get_xidle(%s,%s) returned %dmins idle for %s.", dev, host, (int)idle, user); + closelog(); + } + else if (chk_xterm(dev, host)) return; + else +#endif + idle = (time_now - max(pstat->st_atime, pstat->st_mtime)) / 60; + sesstime = (time_now - utmpp->ut_time) / 60; switch(chk_timeout(user, dev, host, idle, sesstime)) { @@ -951,18 +1078,18 @@ case IDLEMAX: openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); syslog(LOG_NOTICE, - "User %s exceeded idle limit (idle for %d minutes, max=%d).\n", + "User %s exceeded idle limit (idle for %ld minutes, max=%d).\n", user, idle, config[configline]->idlemax); closelog(); - killit(utmpp->ut_pid, user, dev); + killit(utmpp->ut_pid, user, dev, host); break; case SESSMAX: openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); syslog(LOG_NOTICE, - "User %s exceeded maximum session limit (on for %d minutes, max=%d).\n", - user, sesstime, config[configline]->sessmax); + "User %s exceeded maximum session limit at %s (on for %ld minutes, max=%d).\n", + user, dev, sesstime, config[configline]->sessmax); closelog(); - killit(utmpp->ut_pid, user, dev); + killit(utmpp->ut_pid, user, dev, host); break; case DAYMAX: openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); @@ -970,22 +1097,26 @@ "User %s exceeded maximum daily limit (on for %d minutes, max=%d).\n", user, daytime, config[configline]->daymax); closelog(); - killit(utmpp->ut_pid, user, dev); + killit(utmpp->ut_pid, user, dev, host); break; case NOLOGIN: openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); - syslog(LOG_NOTICE, "NOLOGIN period reached for user %s.", user); + #ifdef DEBUG + 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); + #endif closelog(); - killit(utmpp->ut_pid, user, dev); + killit(utmpp->ut_pid, user, dev, host); break; 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(); } } -bailout(message, status) /* display error message and exit */ +void bailout(message, status) /* display error message and exit */ int status; /* exit status */ char *message; /* pointer to the error message */ { @@ -1004,6 +1135,15 @@ exit(0); } +void segfault(signum) +int signum; +{ + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(LOG_NOTICE, "Received SIGSEGV.. Something went wrong! Exiting!"); + closelog(); + exit(0); +} + void logoff_msg(tty) int tty; { @@ -1031,16 +1171,22 @@ } /* terminate process using SIGHUP, then SIGKILL */ -killit(pid, user, dev) +void killit(pid, user, dev, host) int pid; char *user; char *dev; +char *host; { int tty; + pid_t cpid; #ifdef SUNOS struct passwd *pw; #endif + if(chk_xsession(dev, host) && !chk_xterm(dev, host)) { + killit_xsession(utmpp->ut_pid, user, dev); + return; + } /* 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) { @@ -1049,15 +1195,29 @@ closelog(); return; } + + + /* 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); +#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, __LINE__); + closelog(); +#endif + + if(chk_ssh(pid) && chk_ssh(cpid) && !strcmp(getusr(cpid), user)) { +#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, host); + closelog(); +#endif + pid = cpid; + } -/* - if (!strcmp(limit_name, s_nologin)) - fprintf(tty, "\r\n\r\nLogins not allowed at this time. Please try again later.\r\n"); - else - fprintf(tty, "\r\n\r\nYou have exceeded your %s time limit. Logging you off now.\r\n\r\n", - limit_name); - */ logoff_msg(tty); + sleep (KWAIT); /*make sure msg does not get lost, again (esp. ssh)*/ close(tty); #ifdef DEBUG @@ -1145,19 +1305,23 @@ signal(SIGCHLD, reapchild); } -int getdisc(d) +int getdisc(d, host) char *d; +char *host; { int fd; int disc; #ifdef linux + if(chk_xsession(d, host) || chk_xterm(d, host)) + return N_TTY; + if ((fd = open(d, O_RDONLY|O_NONBLOCK|O_NOCTTY)) < 0) { openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); syslog(LOG_WARNING, "Could not open %s for checking line discipline - idle limits will be enforced.", d); closelog(); - return; + return N_TTY; } if (ioctl(fd, TIOCGETD, &disc) < 0) @@ -1166,14 +1330,16 @@ openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); syslog(LOG_WARNING, "Could not get line discipline for %s - idle limits will be enforced.", d); closelog(); - return; + return N_TTY; } close(fd); +#ifdef DEBUG openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); syslog(SYSLOG_DEBUG, "TTY %s: Discipline=%s.",d,disc==N_SLIP?"SLIP":disc==N_TTY?"TTY":disc==N_PPP?"PPP":disc==N_MOUSE?"MOUSE":"UNKNOWN"); closelog(); +#endif return disc; #else @@ -1181,3 +1347,247 @@ #endif } +int chk_xsession(dev, host) /* returns 1 when dev and host seem to be a xSession. */ +char *dev,*host; +{ + if(strncmp(dev, ":0", 1) == 0 && strlen(host) == 0 /*|| + (strncmp(dev, "pts/0", 3) == 0 && strncmp(host, ":0", 1) == 0 )*/) { /* if strings are the same, str[n]cmp returns 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 + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(LOG_DEBUG, "Xsession detected. device=%s host=%s", dev, host); + closelog(); + #endif + return 1; + } + else { + #ifdef DEBUG + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(LOG_DEBUG, "NO xsession detected. device=%s host=%s", dev, host); + closelog(); + #endif + return 0; + } +} + +/* 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) +*/ +int chk_xterm(dev, host) /* returns 1 when dev and host seem to be a xTERM. */ +char *dev,*host; +{ + if(strncmp(dev, "pts/0", 3) == 0 && strncmp(host, ":0", 1) == 0 ) { + #ifdef DEBUG + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(LOG_DEBUG, "XTERM detected. device=%s host=%s Ignoring.", dev, host); + closelog(); + #endif + return 1; + } + else + return 0; +} /* chk_xterm(dev,host) */ + + +void killit_xsession(pid, user, dev) /* returns 1 when dev and host seem to be a xSession. */ +int pid; +char *dev, *user; +{ + char msgbuf[1024], 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]); + } + + /* then send the message using xmessage */ + /* well, this is not really clean: */ + sprintf(cmdbuf, "su %s -c \"xmessage -display %s -center '%s'&\"", user, dev, msgbuf); + system(cmdbuf); + #ifdef DEBUG + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(LOG_DEBUG, "cmdbuf=%s", cmdbuf); + closelog(); + #endif + sleep(KWAIT); /* and give the user some time to read the message ;) */ + + + #ifndef DEBUG + /* kill pid here */ + kill(pid, SIGTERM); /* otherwise, X crashes */ + sleep(KWAIT); + if (!kill(pid, 0)) { /* SIGHUP might be ignored */ + kill(pid, SIGKILL); /* then send sure "kill" signal */ + sleep(KWAIT); + if (!kill(pid, 0)) + { + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(LOG_ERR, "Could not log user %s off line %s. (running X)", user, dev); + closelog(); + } + } + #else + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(LOG_ERR, "Would normally logoff user %s running X (kill PID %d)", user, pid); + closelog(); + #endif +} + + + +int chk_ssh(pid)/* seppy; returns true if pid is sshd, otherwise it returns false */ +pid_t pid; +{ + sprintf(path, "/proc/%d/stat", pid); + proc_file = fopen(path, "r"); + if(!proc_file) { + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(LOG_WARNING, "chk_ssh(): PID %d does not exist. Something went wrong. Ignoring.", pid); + closelog(); + return 0; + } + + fscanf (proc_file, "%*d (%[^)]", comm); + fclose(proc_file); + + if(!strcmp(comm, "sshd")) + return 1; + else + return 0; +} + +char *getusr(pid) /*seppy; returns the name of the user owning process with the Process ID pid */ +pid_t pid; +{ + char uid[99]; + sprintf(path, "/proc/%d/status", pid); + proc_file = fopen(path, "r"); + if(!proc_file) { + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(LOG_NOTICE, "getusr(): PID %d does not exist. Ignoring.", pid); + closelog(); + return "unknown"; + } + while(!fscanf(proc_file, "Uid: %s", uid)) + fgets(uid, 98, proc_file); + fclose(proc_file); + return getpwuid(atoi(uid))->pw_name; +} + +#ifdef TIMEOUTDX11 +Time get_xidle(user, display) /*seppy; returns millicecs since last input event */ +char *user; +char *display; +{ + Display* dpy; + static XScreenSaverInfo* mitInfo = 0; + struct passwd *pwEntry; + char homedir[50]; /*50 should be enough*/ + char oldhomedir[50]; + uid_t oldeuid; + + pwEntry = getpwnam(user); + if(!pwEntry) { + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(LOG_ERR, "Could not get passwd-entry for user %s", user); + closelog(); + } + +#ifdef DEBUG + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(LOG_DEBUG, "su-ing to %s(%d) and connecting to X", user, pwEntry->pw_uid); + closelog(); +#endif + + /*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) { + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(LOG_ERR, "Could not seteuid(%d).", pwEntry->pw_uid); + closelog(); + } + + sprintf(homedir, "HOME=%s", pwEntry->pw_dir); + putenv(homedir); + + /* First, check if there is a xserver.. */ + if (!(dpy = XOpenDisplay (display))) { /* = intended */ + openlog("timeoutd", OPENLOG_FLAGS, LOG_DAEMON); + syslog(LOG_NOTICE, "Could not connect to %s to query idle-time for %s. Ignoring.", display, user); + closelog(); + } + + if (!mitInfo) + mitInfo = XScreenSaverAllocInfo (); + XScreenSaverQueryInfo (dpy, DefaultRootWindow (dpy), mitInfo); + + /*go back again*/ + putenv(oldhomedir); + setuid(oldeuid); + + return mitInfo->idle; +} /* get_xidle(user) */ +#endif + + +/* seppy; getchild() + returns the pid of the first child-process found. + - 1 if a error occured, + - 0 if none found + + 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 */ +pid_t getcpid(ppid) +pid_t ppid; +{ + DIR *proc; + FILE *proc_file; + struct dirent *cont; + char akt_pid[99]; + char path[256]; + + proc = opendir("/proc/"); + if(proc == NULL) { + printf("error opening directory\n"); + return -1; /* error */ + } + + while((cont = readdir(proc)) != NULL) + if(cont->d_type == 4 && 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 */ + } /* if(cont->d_type == 4) */ + + return 0; /* no child found */ +} /* getchild(ppid) */ --- timeoutd-1.5.orig/timeouts +++ timeoutd-1.5/timeouts @@ -1 +1,19 @@ -Al:*:shane:*:NOLOGIN +# /etc/timeouts: user login/idle/session time limits. See timeouts(5). +# +# Format: TIMES:TTYS:USERS:GROUPS:MAXIDLE:MAXSESS:MAXDAY:WARN +# or: TIMES:TTYS:USERS:GROUPS:LOGINSTATUS +# +# Some examples: +# +# dopey is not allowed to login +#Al:*:dopey:*:NOLOGIN +# +# cas gets unlimited use +#Al:*:cas:*:0:0:0:0 +# +# fred is allowed 20 minutes idle, 240 mins per session, and 480 mins per day +# on ttyS3 +#Al:ttyS3:fred:*:20:240:480:10 +# +# everyone else is allowed only 120min/session, 240/day +#Al:ttyS3:*:*:20:120:240:5 --- timeoutd-1.5.orig/timeouts.5 +++ timeoutd-1.5/timeouts.5 @@ -89,10 +89,10 @@ Would match all dialled in users (if all ttyS lines were modems) and prevent them logging in before 7am or after 8pm on weekdays. .SH FILES -/usr/etc/timeouts +/etc/timeouts .SH BUGS See timeoutd(8) .SH "SEE ALSO" .BR timeoutd "(8) .SH "WRITTEN BY" -Shane Alderton +Shane Alderton --- timeoutd-1.5.orig/debian/changelog +++ timeoutd-1.5/debian/changelog @@ -0,0 +1,109 @@ +timeoutd (1.5-9ubuntu1) hoary; urgency=low + + * added libxss-dev to Build-Depends. + + -- Daniel Holbach Thu, 7 Apr 2005 03:42:58 +0200 + +timeoutd (1.5-9) unstable; urgency=low + + * Removed "-m486" because it breaks builds on other archs. + Closes: #231522 + + -- Dennis Stampfer Mon, 1 Mar 2004 20:56:13 +0100 + +timeoutd (1.5-8) unstable; urgency=low + + * timeoutd now complains in logs when segfaulting + * Improofed SSH-Handling + - Wait a few secs to read message before logging out + * No more warnings when compiling + * Now depends on xlibs + - timeoutd is able to querry X for idle time. Closes: #222287 + * Improofed description + * Corrected debian/copyright + * Conforms to Standards version 3.6.1 + + -- Dennis Stampfer Fri, 2 Jan 2004 00:11:09 +0100 + +timeoutd (1.5-7) unstable; urgency=low + + * Upstream author's adress outdated. Changed address. + * Restrictions are now possible for users running X. + * telnet sessions are handled like tty. Closes: #194917 + * ssh restrictions are possible from now on. + * Conforms to Standards version 3.6.0 + + -- Dennis Stampfer Sun, 01 Jun 2003 16:27:00 +0200 + +timeoutd (1.5-6) unstable; urgency=low + + * timeoutd runs now also when a X-Session is running. Closes: #191575 + * Conforms to Standards version 3.5.9.0 + + -- Dennis Stampfer Sat, 10 May 2003 15:28:35 +0200 + +timeoutd (1.5-5) unstable; urgency=low + + * New Maintainer. Closes: #158333 + * Conforms to Standards version 3.5.8.0 + * Improved description. + + -- Dennis Stampfer Wed, 4 Dec 2002 18:32:37 +0100 + +timeoutd (1.5-4) unstable; urgency=low + + * QA upload. + * Package is orphaned (see #158333); set maintainer to Debian QA Group. + * timeoutd.c: + - Determine utmp field sizes with sizeof instead of using traditional + values. Closes: #52456. + - Open terminal device with O_NONBLOCK. Closes: #30980. + - Do `chdir("/dev")' to avoid `device busy' errors when the filesystem + from which we were started is unmounted. + - Fix some more warnings. + * timeouts: Add format summary. Closes: #126543. + * Drop dump_wtmp -- last(1) is so much better. Closes: #22775. + * Why was timeoutd setgid root? It must be run as root anyway to kill + other users' processes... + * Add build dependencies. Closes: #95039. + * Switch from debstd to debhelper. + * debian/copyright: + - Note that the upstream URL is outdated and that the author's e-mail + bounces. Closes: #131085. + - Refer to /usr/share/common-licenses/GPL. + * debian/init.d: Update from current /etc/init.d/skeleton. Uses a delay + between starting and stopping. Closes: #30979. + * debian/README.debian: Everything already said in copyright; remove. + * debian/changelog: Remove obsolete Emacs local variables. + * Conforms to Standards version 3.5.6. + + -- Matej Vela Thu, 29 Aug 2002 04:26:45 +0200 + +timeoutd (1.5-3) unstable; urgency=low + + * Non-Maintainer upload + * rebuild to move /usr/doc to /usr/share/doc (Closes: #91677) + * indented Description + * updated FSF address in copyright + * marked init.d script as conffile + * added isp flags to dpkg-gencontrol to create Section: and Priority: + fields + * tweaked init.d script to provide a force-reload + * upped standards version + + -- Stephen Stafford Sat, 21 Apr 2001 22:26:37 +0100 + +timeoutd (1.5-2) unstable; urgency=low + + * recompiled for libc6 + * now includes dump_wtmp binary + * cleaned up some compiler warnings + * added reload and restart args to /etc/init.d/timeoutd + + -- Craig Sanders Sat, 8 Nov 1997 13:18:47 +1100 + +timeoutd (1.5-1) unstable; urgency=low + + * Initial Release. + + -- Craig Sanders Sat, 22 Feb 1997 15:20:11 +1100 --- timeoutd-1.5.orig/debian/compat +++ timeoutd-1.5/debian/compat @@ -0,0 +1 @@ +4 --- timeoutd-1.5.orig/debian/control +++ timeoutd-1.5/debian/control @@ -0,0 +1,26 @@ +Source: timeoutd +Section: admin +Priority: extra +Maintainer: Dennis Stampfer +Standards-Version: 3.6.1.0 +Build-Depends: debhelper (>= 4), xlibs-dev, libxss-dev + +Package: timeoutd +Architecture: any +Depends: ${shlibs:Depends} +Conflicts: suidmanager (<< 0.50) +Description: Flexible user timeout daemon with X11 support + timeoutd enforces the time restrictions specified for each or all users. + . + timeoutd scans /var/run/utmp every minute and checks /etc/timeouts for + an entry which matches a restricted user, based on: + . + - The current day and time + - The tty that the user is currently logged in on + - The user's login ID + - Any primary or secondary groups the user is in + timeoutd can restrict local users, local X11-users and remote users via + telnet/SSH for a maximum of their session, max. day, idle or no login at + all. + . + timeoutd is also able to restrict users running X. --- timeoutd-1.5.orig/debian/copyright +++ timeoutd-1.5/debian/copyright @@ -0,0 +1,35 @@ +This package was debianized by Craig Sanders on +Sat, 22 Feb 1997 15:20:11 +1100. + +It is maintained by Dennis Stampfer since +Wed, 4 Dec 2002 18:32:37 +0100 + +It was downloaded from ion.apana.org.au. Unfortunately, this address is +outdated. It is not developed upstream anymore. + +Author: Shane Alderton + +Copyright 1997 Shane Alderton + +Maintainers worked on timeoutd for Debian: + 1997 Craig Sanders + 2001 Stephen Stafford + 2002 Matej Vela + 2002, 2003, 2004 Dennis Stampfer + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +On Debian systems, the complete text of the GNU General Public License +can be found in /usr/share/common-licenses/GPL. --- timeoutd-1.5.orig/debian/init.d +++ timeoutd-1.5/debian/init.d @@ -0,0 +1,44 @@ +#! /bin/sh +# /etc/init.d/timeoutd: start and stop the user timeout daemon. +# +# Based on skeleton 1.9.1 by Miquel van Smoorenburg . + +DAEMON=/usr/sbin/timeoutd +NAME=timeoutd +DESC="user timeout daemon" + +test -x $DAEMON || exit 0 + +set -e + +case "$1" in + start) + echo -n "Starting $DESC: $NAME" + start-stop-daemon --start --oknodo --quiet --exec $DAEMON + echo "." + ;; + stop) + echo -n "Stopping $DESC: $NAME" + start-stop-daemon --stop --oknodo --quiet --exec $DAEMON + echo "." + ;; + reload|force-reload) + echo -n "Reloading $DESC configuration..." + start-stop-daemon --stop --signal 1 --quiet --exec $DAEMON + echo "done." + ;; + restart) + echo -n "Restarting $DESC: $NAME" + start-stop-daemon --stop --oknodo --quiet --exec $DAEMON + sleep 1 + start-stop-daemon --start --quiet --exec $DAEMON + echo "." + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 --- timeoutd-1.5.orig/debian/rules +++ timeoutd-1.5/debian/rules @@ -0,0 +1,64 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# This file is public domain software, originally written by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +build: + $(MAKE) timeoutd + +clean: + dh_testdir + dh_testroot + + # Add here commands to clean up after the build process. + rm -f timeoutd timeoutd.o + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/ + dh_install + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs + dh_installdocs +# dh_installexamples +# dh_installmenu +# dh_installdebconf +# dh_installlogrotate +# dh_installemacsen +# dh_installpam +# dh_installmime + dh_installinit +# dh_installcron +# dh_installinfo +# dh_undocumented + dh_installman +# dh_link + dh_strip + dh_compress + dh_fixperms +# dh_makeshlibs + dh_installdeb +# dh_perl + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install --- timeoutd-1.5.orig/debian/timeoutd.manpages +++ timeoutd-1.5/debian/timeoutd.manpages @@ -0,0 +1 @@ +timeoutd.8 timeouts.5 --- timeoutd-1.5.orig/debian/timeoutd.docs +++ timeoutd-1.5/debian/timeoutd.docs @@ -0,0 +1 @@ +README --- timeoutd-1.5.orig/debian/timeoutd.install +++ timeoutd-1.5/debian/timeoutd.install @@ -0,0 +1,2 @@ +timeoutd usr/sbin +timeouts etc --- timeoutd-1.5.orig/debian/timeoutd.init.d +++ timeoutd-1.5/debian/timeoutd.init.d @@ -0,0 +1,44 @@ +#! /bin/sh +# /etc/init.d/timeoutd: start and stop the user timeout daemon. +# +# Based on skeleton 1.9.1 by Miquel van Smoorenburg . + +DAEMON=/usr/sbin/timeoutd +NAME=timeoutd +DESC="user timeout daemon" + +test -x $DAEMON || exit 0 + +set -e + +case "$1" in + start) + echo -n "Starting $DESC: $NAME" + start-stop-daemon --start --oknodo --quiet --exec $DAEMON + echo "." + ;; + stop) + echo -n "Stopping $DESC: $NAME" + start-stop-daemon --stop --oknodo --quiet --exec $DAEMON + echo "." + ;; + reload|force-reload) + echo -n "Reloading $DESC configuration..." + start-stop-daemon --stop --signal 1 --quiet --exec $DAEMON + echo "done." + ;; + restart) + echo -n "Restarting $DESC: $NAME" + start-stop-daemon --stop --oknodo --quiet --exec $DAEMON + sleep 1 + start-stop-daemon --start --quiet --exec $DAEMON + echo "." + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0