]> granicus.if.org Git - shadow/blob - src/logoutd.c
* src/logoutd.c: Use a bool when possible instead of int integers.
[shadow] / src / logoutd.c
1 /*
2  * Copyright (c) 1991 - 1993, Julianne Frances Haugh
3  * Copyright (c) 1996 - 2000, Marek Michałkiewicz
4  * Copyright (c) 2001 - 2006, Tomasz Kłoczko
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the copyright holders or contributors may not be used to
16  *    endorse or promote products derived from this software without
17  *    specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
23  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <config.h>
33
34 #ident "$Id$"
35
36 #include <fcntl.h>
37 #include <signal.h>
38 #include <stdio.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include "defines.h"
42 #include "prototypes.h"
43 /*
44  * Global variables
45  */
46 static char *Prog;
47
48 #ifndef DEFAULT_HUP_MESG
49 #define DEFAULT_HUP_MESG _("login time exceeded\n\n")
50 #endif
51
52 #ifndef HUP_MESG_FILE
53 #define HUP_MESG_FILE "/etc/logoutd.mesg"
54 #endif
55
56 #if HAVE_UTMPX_H
57 static int check_login (const struct utmpx *);
58 #else
59 static int check_login (const struct utmp *);
60 #endif
61
62 /*
63  * check_login - check if user (struct utmpx/utmp) allowed to stay logged in
64  */
65 #if HAVE_UTMPX_H
66 static int check_login (const struct utmpx *ut)
67 #else
68 static int check_login (const struct utmp *ut)
69 #endif
70 {
71         char user[sizeof (ut->ut_user) + 1];
72         time_t now;
73
74         /*
75          * ut_user may not have the terminating NUL.
76          */
77         strncpy (user, ut->ut_user, sizeof (ut->ut_user));
78         user[sizeof (ut->ut_user)] = '\0';
79
80         time (&now);
81
82         /*
83          * Check if they are allowed to be logged in right now.
84          */
85         if (!isttytime (user, ut->ut_line, now)) {
86                 return 0;
87         }
88         return 1;
89 }
90
91
92 static void send_mesg_to_tty (int tty_fd)
93 {
94         TERMIO oldt, newt;
95         FILE *mesg_file, *tty_file;
96         int c;
97         bool is_tty;
98
99         tty_file = fdopen (tty_fd, "w");
100         if (NULL == tty_file) {
101                 return;
102         }
103
104         is_tty = (GTTY (tty_fd, &oldt) == 0);
105         if (is_tty) {
106                 /* Suggested by Ivan Nejgebauar <ian@unsux.ns.ac.yu>:
107                    set OPOST before writing the message. */
108                 newt = oldt;
109                 newt.c_oflag |= OPOST;
110                 STTY (tty_fd, &newt);
111         }
112
113         mesg_file = fopen (HUP_MESG_FILE, "r");
114         if (NULL != mesg_file) {
115                 while ((c = getc (mesg_file)) != EOF) {
116                         if (c == '\n') {
117                                 putc ('\r', tty_file);
118                         }
119                         putc (c, tty_file);
120                 }
121                 fclose (mesg_file);
122         } else {
123                 fputs (DEFAULT_HUP_MESG, tty_file);
124         }
125         fflush (tty_file);
126         fclose (tty_file);
127
128         if (is_tty) {
129                 STTY (tty_fd, &oldt);
130         }
131 }
132
133
134 /*
135  * logoutd - logout daemon to enforce /etc/porttime file policy
136  *
137  *      logoutd is started at system boot time and enforces the login
138  *      time and port restrictions specified in /etc/porttime. The
139  *      utmpx/utmp file is periodically scanned and offending users are logged
140  *      off from the system.
141  */
142 int main (int argc, char **argv)
143 {
144         int i;
145         int status;
146         pid_t pid;
147
148 #if HAVE_UTMPX_H
149         struct utmpx *ut;
150 #else
151         struct utmp *ut;
152 #endif
153         char user[sizeof (ut->ut_user) + 1];    /* terminating NUL */
154         char tty_name[sizeof (ut->ut_line) + 6];        /* /dev/ + NUL */
155         int tty_fd;
156
157         (void) setlocale (LC_ALL, "");
158         (void) bindtextdomain (PACKAGE, LOCALEDIR);
159         (void) textdomain (PACKAGE);
160
161 #ifndef DEBUG
162         for (i = 0; close (i) == 0; i++);
163
164         setpgrp ();
165
166         /*
167          * Put this process in the background.
168          */
169         pid = fork ();
170         if (pid > 0) {
171                 /* parent */
172                 exit (0);
173         } else if (pid < 0) {
174                 /* error */
175                 perror ("fork");
176                 exit (1);
177         }
178 #endif                          /* !DEBUG */
179
180         /*
181          * Start syslogging everything
182          */
183         Prog = Basename (argv[0]);
184
185         OPENLOG ("logoutd");
186
187         /*
188          * Scan the utmpx/utmp file once per minute looking for users that
189          * are not supposed to still be logged in.
190          */
191         while (true) {
192
193                 /* 
194                  * Attempt to re-open the utmpx/utmp file. The file is only
195                  * open while it is being used.
196                  */
197 #if HAVE_UTMPX_H
198                 setutxent ();
199 #else
200                 setutent ();
201 #endif
202
203                 /*
204                  * Read all of the entries in the utmpx/utmp file. The entries
205                  * for login sessions will be checked to see if the user
206                  * is permitted to be signed on at this time.
207                  */
208 #if HAVE_UTMPX_H
209                 while ((ut = getutxent ()) != NULL) {
210 #else
211                 while ((ut = getutent ()) != NULL) {
212 #endif
213                         if (ut->ut_type != USER_PROCESS) {
214                                 continue;
215                         }
216                         if (ut->ut_user[0] == '\0') {
217                                 continue;
218                         }
219                         if (check_login (ut)) {
220                                 continue;
221                         }
222
223                         /*
224                          * Put the rest of this in a child process. This
225                          * keeps the scan from waiting on other ports to die.
226                          */
227
228                         pid = fork ();
229                         if (pid > 0) {
230                                 /* parent */
231                                 continue;
232                         } else if (pid < 0) {
233                                 /* failed - give up until the next scan */
234                                 break;
235                         }
236                         /* child */
237
238                         if (strncmp (ut->ut_line, "/dev/", 5) != 0) {
239                                 strcpy (tty_name, "/dev/");
240                         } else {
241                                 tty_name[0] = '\0';
242                         }
243
244                         strcat (tty_name, ut->ut_line);
245 #ifndef O_NOCTTY
246 #define O_NOCTTY 0
247 #endif
248                         tty_fd =
249                             open (tty_name, O_WRONLY | O_NDELAY | O_NOCTTY);
250                         if (tty_fd != -1) {
251                                 send_mesg_to_tty (tty_fd);
252                                 close (tty_fd);
253                                 sleep (10);
254                         }
255
256                         if (ut->ut_pid > 1) {
257                                 kill (-ut->ut_pid, SIGHUP);
258                                 sleep (10);
259                                 kill (-ut->ut_pid, SIGKILL);
260                         }
261
262                         strncpy (user, ut->ut_user, sizeof (user) - 1);
263                         user[sizeof (user) - 1] = '\0';
264
265                         SYSLOG ((LOG_NOTICE,
266                                  "logged off user `%s' on `%s'", user,
267                                  tty_name));
268
269                         /*
270                          * This child has done all it can, drop dead.
271                          */
272                         exit (0);
273                 }
274
275 #if HAVE_UTMPX_H
276                 endutxent ();
277 #else
278                 endutent ();
279 #endif
280
281 #ifndef DEBUG
282                 sleep (60);
283 #endif
284                 /*
285                  * Reap any dead babies ...
286                  */
287                 while (wait (&status) != -1);
288         }
289         return 1;
290         /* NOT REACHED */
291 }
292