]> granicus.if.org Git - shadow/blob - libmisc/utmp.c
(failcheck): The failed argument is a bool.
[shadow] / libmisc / utmp.c
1 /*
2  * Copyright (c) 1989 - 1994, Julianne Frances Haugh
3  * Copyright (c) 1996 - 1999, Marek Michałkiewicz
4  * Copyright (c) 2001 - 2005, Tomasz Kłoczko
5  * Copyright (c) 2008       , Nicolas François
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the copyright holders or contributors may not be used to
17  *    endorse or promote products derived from this software without
18  *    specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <config.h>
34
35 #include "defines.h"
36 #include "prototypes.h"
37
38 #include <utmp.h>
39
40 #if HAVE_UTMPX_H
41 #include <utmpx.h>
42 #endif
43
44 #include <fcntl.h>
45 #include <stdio.h>
46
47 #ident "$Id$"
48
49 #if HAVE_UTMPX_H
50 struct utmpx utxent;
51 #endif
52 struct utmp utent;
53
54 #define NO_UTENT \
55         _("No utmp entry.  You must exec \"login\" from the lowest level \"sh\"")
56 #define NO_TTY \
57         _("Unable to determine your tty name.")
58
59 /*
60  * checkutmp - see if utmp file is correct for this process
61  *
62  *      System V is very picky about the contents of the utmp file
63  *      and requires that a slot for the current process exist.
64  *      The utmp file is scanned for an entry with the same process
65  *      ID.  If no entry exists the process exits with a message.
66  *
67  *      The "picky" flag is for network and other logins that may
68  *      use special flags.  It allows the pid checks to be overridden.
69  *      This means that getty should never invoke login with any
70  *      command line flags.
71  */
72
73 #if defined(__linux__)          /* XXX */
74
75 void checkutmp (int picky)
76 {
77         char *line;
78         struct utmp *ut;
79         pid_t pid = getpid ();
80
81         setutent ();
82
83         /* First, try to find a valid utmp entry for this process.  */
84         while ((ut = getutent ()))
85                 if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] &&
86                     (ut->ut_type == LOGIN_PROCESS
87                      || ut->ut_type == USER_PROCESS))
88                         break;
89
90         /* If there is one, just use it, otherwise create a new one.  */
91         if (ut) {
92                 utent = *ut;
93         } else {
94                 if (picky) {
95                         puts (NO_UTENT);
96                         exit (1);
97                 }
98                 line = ttyname (0);
99                 if (!line) {
100                         puts (NO_TTY);
101                         exit (1);
102                 }
103                 if (strncmp (line, "/dev/", 5) == 0)
104                         line += 5;
105                 memset ((void *) &utent, 0, sizeof utent);
106                 utent.ut_type = LOGIN_PROCESS;
107                 utent.ut_pid = pid;
108                 strncpy (utent.ut_line, line, sizeof utent.ut_line);
109                 /* XXX - assumes /dev/tty?? */
110                 strncpy (utent.ut_id, utent.ut_line + 3, sizeof utent.ut_id);
111                 strcpy (utent.ut_user, "LOGIN");
112                 utent.ut_time = time (NULL);
113         }
114 }
115
116 #elif defined(LOGIN_PROCESS)
117
118 void checkutmp (bool picky)
119 {
120         char *line;
121         struct utmp *ut;
122
123 #if HAVE_UTMPX_H
124         struct utmpx *utx;
125 #endif
126         pid_t pid = getpid ();
127
128 #if HAVE_UTMPX_H
129         setutxent ();
130 #endif
131         setutent ();
132
133         if (picky) {
134 #if HAVE_UTMPX_H
135                 while ((utx = getutxent ()))
136                         if (utx->ut_pid == pid)
137                                 break;
138
139                 if (utx)
140                         utxent = *utx;
141 #endif
142                 while ((ut = getutent ()))
143                         if (ut->ut_pid == pid)
144                                 break;
145
146                 if (ut)
147                         utent = *ut;
148
149 #if HAVE_UTMPX_H
150                 endutxent ();
151 #endif
152                 endutent ();
153
154                 if (!ut) {
155                         puts (NO_UTENT);
156                         exit (1);
157                 }
158 #ifndef UNIXPC
159
160                 /*
161                  * If there is no ut_line value in this record, fill
162                  * it in by getting the TTY name and stuffing it in
163                  * the structure.  The UNIX/PC is broken in this regard
164                  * and needs help ...
165                  */
166
167                 if (utent.ut_line[0] == '\0')
168 #endif                          /* !UNIXPC */
169                 {
170                         if (!(line = ttyname (0))) {
171                                 puts (NO_TTY);
172                                 exit (1);
173                         }
174                         if (strncmp (line, "/dev/", 5) == 0)
175                                 line += 5;
176                         strncpy (utent.ut_line, line, sizeof utent.ut_line);
177 #if HAVE_UTMPX_H
178                         strncpy (utxent.ut_line, line, sizeof utxent.ut_line);
179 #endif
180                 }
181         } else {
182                 if (!(line = ttyname (0))) {
183                         puts (NO_TTY);
184                         exit (1);
185                 }
186                 if (strncmp (line, "/dev/", 5) == 0)
187                         line += 5;
188
189                 strncpy (utent.ut_line, line, sizeof utent.ut_line);
190                 if ((ut = getutline (&utent)))
191                         strncpy (utent.ut_id, ut->ut_id, sizeof ut->ut_id);
192
193                 strcpy (utent.ut_user, "LOGIN");
194                 utent.ut_pid = getpid ();
195                 utent.ut_type = LOGIN_PROCESS;
196                 utent.ut_time = time (NULL);
197 #if HAVE_UTMPX_H
198                 strncpy (utxent.ut_line, line, sizeof utxent.ut_line);
199                 if ((utx = getutxline (&utxent)))
200                         strncpy (utxent.ut_id, utx->ut_id, sizeof utxent.ut_id);
201
202                 strcpy (utxent.ut_user, "LOGIN");
203                 utxent.ut_pid = utent.ut_pid;
204                 utxent.ut_type = utent.ut_type;
205                 if (sizeof (utxent.ut_tv) == sizeof (struct timeval))
206                         gettimeofday ((struct timeval *) &utxent.ut_tv, NULL);
207                 else {
208                         struct timeval tv;
209
210                         gettimeofday (&tv, NULL);
211                         utxent.ut_tv.tv_sec = tv.tv_sec;
212                         utxent.ut_tv.tv_usec = tv.tv_usec;
213                 }
214                 utent.ut_time = utxent.ut_tv.tv_sec;
215 #endif
216         }
217 }
218
219 #endif
220
221
222 /*
223  * Some systems already have updwtmp() and possibly updwtmpx().  Others
224  * don't, so we re-implement these functions if necessary.  --marekm
225  */
226
227 #ifndef HAVE_UPDWTMP
228 static void updwtmp (const char *filename, const struct utmp *ut)
229 {
230         int fd;
231
232         fd = open (filename, O_APPEND | O_WRONLY, 0);
233         if (fd >= 0) {
234                 write (fd, (const char *) ut, sizeof (*ut));
235                 close (fd);
236         }
237 }
238 #endif                          /* ! HAVE_UPDWTMP */
239
240 #ifdef HAVE_UTMPX_H
241 #ifndef HAVE_UPDWTMPX
242 static void updwtmpx (const char *filename, const struct utmpx *utx)
243 {
244         int fd;
245
246         fd = open (filename, O_APPEND | O_WRONLY, 0);
247         if (fd >= 0) {
248                 write (fd, (const char *) utx, sizeof (*utx));
249                 close (fd);
250         }
251 }
252 #endif                          /* ! HAVE_UPDWTMPX */
253 #endif                          /* ! HAVE_UTMPX_H */
254
255
256 /*
257  * setutmp - put a USER_PROCESS entry in the utmp file
258  *
259  *      setutmp changes the type of the current utmp entry to
260  *      USER_PROCESS.  the wtmp file will be updated as well.
261  */
262
263 #if defined(__linux__)          /* XXX */
264
265 void setutmp (const char *name, const char *line, const char *host)
266 {
267         utent.ut_type = USER_PROCESS;
268         strncpy (utent.ut_user, name, sizeof utent.ut_user);
269         utent.ut_time = time (NULL);
270         /* other fields already filled in by checkutmp above */
271         setutent ();
272         pututline (&utent);
273         endutent ();
274         updwtmp (_WTMP_FILE, &utent);
275 }
276
277 #elif HAVE_UTMPX_H
278
279 void setutmp (const char *name, const char *line, const char *host)
280 {
281         struct utmp *utmp, utline;
282         struct utmpx *utmpx, utxline;
283         pid_t pid = getpid ();
284         bool found_utmpx = false, found_utmp = false;
285
286         /*
287          * The canonical device name doesn't include "/dev/"; skip it
288          * if it is already there.
289          */
290
291         if (strncmp (line, "/dev/", 5) == 0)
292                 line += 5;
293
294         /*
295          * Update utmpx.  We create an empty entry in case there is
296          * no matching entry in the utmpx file.
297          */
298
299         setutxent ();
300         setutent ();
301
302         while (utmpx = getutxent ()) {
303                 if (utmpx->ut_pid == pid) {
304                         found_utmpx = true;
305                         break;
306                 }
307         }
308         while (utmp = getutent ()) {
309                 if (utmp->ut_pid == pid) {
310                         found_utmp = true;
311                         break;
312                 }
313         }
314
315         /*
316          * If the entry matching `pid' cannot be found, create a new
317          * entry with the device name in it.
318          */
319
320         if (!found_utmpx) {
321                 memset ((void *) &utxline, 0, sizeof utxline);
322                 strncpy (utxline.ut_line, line, sizeof utxline.ut_line);
323                 utxline.ut_pid = getpid ();
324         } else {
325                 utxline = *utmpx;
326                 if (strncmp (utxline.ut_line, "/dev/", 5) == 0) {
327                         memmove (utxline.ut_line, utxline.ut_line + 5,
328                                  sizeof utxline.ut_line - 5);
329                         utxline.ut_line[sizeof utxline.ut_line - 5] = '\0';
330                 }
331         }
332         if (!found_utmp) {
333                 memset ((void *) &utline, 0, sizeof utline);
334                 strncpy (utline.ut_line, utxline.ut_line,
335                          sizeof utline.ut_line);
336                 utline.ut_pid = utxline.ut_pid;
337         } else {
338                 utline = *utmp;
339                 if (strncmp (utline.ut_line, "/dev/", 5) == 0) {
340                         memmove (utline.ut_line, utline.ut_line + 5,
341                                  sizeof utline.ut_line - 5);
342                         utline.ut_line[sizeof utline.ut_line - 5] = '\0';
343                 }
344         }
345
346         /*
347          * Fill in the fields in the utmpx entry and write it out.  Do
348          * the utmp entry at the same time to make sure things don't
349          * get messed up.
350          */
351
352         strncpy (utxline.ut_user, name, sizeof utxline.ut_user);
353         strncpy (utline.ut_user, name, sizeof utline.ut_user);
354
355         utline.ut_type = utxline.ut_type = USER_PROCESS;
356
357         if (sizeof (utxline.ut_tv) == sizeof (struct timeval))
358                 gettimeofday ((struct timeval *) &utxline.ut_tv, NULL);
359         else {
360                 struct timeval tv;
361
362                 gettimeofday (&tv, NULL);
363                 utxline.ut_tv.tv_sec = tv.tv_sec;
364                 utxline.ut_tv.tv_usec = tv.tv_usec;
365         }
366         utline.ut_time = utxline.ut_tv.tv_sec;
367
368         strncpy (utxline.ut_host, host ? host : "", sizeof utxline.ut_host);
369
370         pututxline (&utxline);
371         pututline (&utline);
372         /* TODO: log failures */
373
374         updwtmpx (_WTMP_FILE "x", &utxline);
375         updwtmp (_WTMP_FILE, &utline);
376
377         utxent = utxline;
378         utent = utline;
379 }
380
381 #endif