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 - 2009, Nicolas François
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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.
36 #include "prototypes.h"
48 #ident "$Id: utmp.c 2834 2009-04-28 20:03:23Z nekral-guest $"
52 * is_my_tty -- determine if "tty" is the same TTY stdin is using
54 static bool is_my_tty (const char *tty)
56 /* full_tty shall be at least sizeof utmp.ut_line + 5 */
58 /* tmptty shall be bigger than full_tty */
59 static char tmptty[sizeof (full_tty)+1];
62 (void) snprintf (full_tty, sizeof full_tty, "/dev/%s", tty);
66 if ('\0' == tmptty[0]) {
67 const char *tname = ttyname (STDIN_FILENO);
69 (void) strncpy (tmptty, tname, sizeof tmptty);
70 tmptty[sizeof (tmptty) - 1] = '\0';
75 (void) puts (_("Unable to determine your tty name."));
77 } else if (strncmp (tty, tmptty, sizeof (tmptty)) != 0) {
85 * get_current_utmp - return the most probable utmp entry for the current
88 * The utmp file is scanned for an entry with the same process ID.
89 * The line enterred by the *getty / telnetd, etc. should also match
90 * the current terminal.
92 * When an entry is returned by get_current_utmp, and if the utmp
93 * structure has a ut_id field, this field should be used to update
94 * the entry information.
96 * Return NULL if no entries exist in utmp for the current process.
98 /*@null@*/ /*@only@*/struct utmp *get_current_utmp (void)
101 struct utmp *ret = NULL;
105 /* First, try to find a valid utmp entry for this process. */
106 while ((ut = getutent ()) != NULL) {
107 if ( (ut->ut_pid == getpid ())
108 #ifdef HAVE_STRUCT_UTMP_UT_ID
109 && ('\0' != ut->ut_id[0])
111 #ifdef HAVE_STRUCT_UTMP_UT_TYPE
112 && ( (LOGIN_PROCESS == ut->ut_type)
113 || (USER_PROCESS == ut->ut_type))
115 /* A process may have failed to close an entry
116 * Check if this entry refers to the current tty */
117 && is_my_tty (ut->ut_line)) {
123 ret = (struct utmp *) xmalloc (sizeof (*ret));
124 memcpy (ret, ut, sizeof (*ret));
133 * Some systems already have updwtmp() and possibly updwtmpx(). Others
134 * don't, so we re-implement these functions if necessary.
137 static void updwtmp (const char *filename, const struct utmp *ut)
141 fd = open (filename, O_APPEND | O_WRONLY, 0);
143 write (fd, (const char *) ut, sizeof (*ut));
147 #endif /* ! HAVE_UPDWTMP */
150 #ifndef HAVE_UPDWTMPX
151 static void updwtmpx (const char *filename, const struct utmpx *utx)
155 fd = open (filename, O_APPEND | O_WRONLY, 0);
157 write (fd, (const char *) utx, sizeof (*utx));
161 #endif /* ! HAVE_UPDWTMPX */
162 #endif /* ! USE_UTMPX */
166 * prepare_utmp - prepare an utmp entry so that it can be logged in a
169 * It accepts an utmp entry in input (ut) to return an entry with
170 * the right ut_id. This is typically an entry returned by
172 * If ut is NULL, ut_id will be forged based on the line argument.
174 * The ut_host field of the input structure may also be kept, and is
175 * used to define the ut_addr/ut_addr_v6 fields. (if these fields
178 * Other fields are discarded and filed with new values (if they
181 * The returned structure shall be freed by the caller.
183 /*@only@*/struct utmp *prepare_utmp (const char *name,
186 /*@null@*/const struct utmp *ut)
189 char *hostname = NULL;
192 assert (NULL != name);
193 assert (NULL != line);
198 && ('\0' != host[0])) {
199 hostname = (char *) xmalloc (strlen (host) + 1);
200 strcpy (hostname, host);
201 #ifdef HAVE_STRUCT_UTMP_UT_HOST
202 } else if ( (NULL != ut)
203 && (NULL != ut->ut_host)
204 && ('\0' != ut->ut_host[0])) {
205 hostname = (char *) xmalloc (sizeof (ut->ut_host) + 1);
206 strncpy (hostname, ut->ut_host, sizeof (ut->ut_host));
207 hostname[sizeof (ut->ut_host)] = '\0';
208 #endif /* HAVE_STRUCT_UTMP_UT_HOST */
211 if (strncmp(line, "/dev/", 5) == 0) {
216 utent = (struct utmp *) xmalloc (sizeof (*utent));
217 memzero (utent, sizeof (*utent));
221 #ifdef HAVE_STRUCT_UTMP_UT_TYPE
222 utent->ut_type = USER_PROCESS;
223 #endif /* HAVE_STRUCT_UTMP_UT_TYPE */
224 utent->ut_pid = getpid ();
225 strncpy (utent->ut_line, line, sizeof (utent->ut_line));
226 #ifdef HAVE_STRUCT_UTMP_UT_ID
228 strncpy (utent->ut_id, ut->ut_id, sizeof (utent->ut_id));
230 /* XXX - assumes /dev/tty?? */
231 strncpy (utent->ut_id, line + 3, sizeof (utent->ut_id));
233 #endif /* HAVE_STRUCT_UTMP_UT_ID */
234 #ifdef HAVE_STRUCT_UTMP_UT_NAME
235 strncpy (utent->ut_name, name, sizeof (utent->ut_name));
236 #endif /* HAVE_STRUCT_UTMP_UT_NAME */
237 #ifdef HAVE_STRUCT_UTMP_UT_USER
238 strncpy (utent->ut_user, name, sizeof (utent->ut_user));
239 #endif /* HAVE_STRUCT_UTMP_UT_USER */
240 if (NULL != hostname) {
241 struct addrinfo *info = NULL;
242 #ifdef HAVE_STRUCT_UTMP_UT_HOST
243 strncpy (utent->ut_host, hostname, sizeof (utent->ut_host));
244 #endif /* HAVE_STRUCT_UTMP_UT_HOST */
245 #ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
246 utent->ut_syslen = MIN (strlen (hostname),
247 sizeof (utent->ut_host));
248 #endif /* HAVE_STRUCT_UTMP_UT_SYSLEN */
249 #if defined(HAVE_STRUCT_UTMP_UT_ADDR) || defined(HAVE_STRUCT_UTMP_UT_ADDR_V6)
250 if (getaddrinfo (hostname, NULL, NULL, &info) == 0) {
251 /* getaddrinfo might not be reliable.
252 * Just try to log what may be useful.
254 if (info->ai_family == AF_INET) {
255 struct sockaddr_in *sa =
256 (struct sockaddr_in *) info->ai_addr;
257 #ifdef HAVE_STRUCT_UTMP_UT_ADDR
258 memcpy (&(utent->ut_addr),
260 MIN (sizeof (utent->ut_addr),
261 sizeof (sa->sin_addr)));
262 #endif /* HAVE_STRUCT_UTMP_UT_ADDR */
263 #ifdef HAVE_STRUCT_UTMP_UT_ADDR_V6
264 memcpy (utent->ut_addr_v6,
266 MIN (sizeof (utent->ut_addr_v6),
267 sizeof (sa->sin_addr)));
268 } else if (info->ai_family == AF_INET6) {
269 struct sockaddr_in6 *sa =
270 (struct sockaddr_in6 *) info->ai_addr;
271 memcpy (utent->ut_addr_v6,
273 MIN (sizeof (utent->ut_addr_v6),
274 sizeof (sa->sin6_addr)));
275 #endif /* HAVE_STRUCT_UTMP_UT_ADDR_V6 */
279 #endif /* HAVE_STRUCT_UTMP_UT_ADDR || HAVE_STRUCT_UTMP_UT_ADDR_V6 */
282 /* ut_exit is only for DEAD_PROCESS */
283 utent->ut_session = getsid (0);
284 if (gettimeofday (&tv, NULL) == 0) {
285 #ifdef HAVE_STRUCT_UTMP_UT_TIME
286 utent->ut_time = tv.tv_sec;
287 #endif /* HAVE_STRUCT_UTMP_UT_TIME */
288 #ifdef HAVE_STRUCT_UTMP_UT_XTIME
289 utent->ut_xtime = tv.tv_usec;
290 #endif /* HAVE_STRUCT_UTMP_UT_XTIME */
291 #ifdef HAVE_STRUCT_UTMP_UT_TV
292 utent->ut_tv.tv_sec = tv.tv_sec;
293 utent->ut_tv.tv_usec = tv.tv_usec;
294 #endif /* HAVE_STRUCT_UTMP_UT_TV */
301 * setutmp - Update an entry in utmp and log an entry in wtmp
303 * Return 1 on failure and 0 on success.
305 int setutmp (struct utmp *ut)
312 if (pututline (ut) == NULL) {
317 updwtmp (_WTMP_FILE, ut);
324 * prepare_utmpx - the UTMPX version for prepare_utmp
326 /*@only@*/struct utmpx *prepare_utmpx (const char *name,
329 /*@null@*/const struct utmp *ut)
332 char *hostname = NULL;
333 struct utmpx *utxent;
335 assert (NULL != name);
336 assert (NULL != line);
341 && ('\0' != host[0])) {
342 hostname = (char *) xmalloc (strlen (host) + 1);
343 strcpy (hostname, host);
344 #ifdef HAVE_STRUCT_UTMP_UT_HOST
345 } else if ( (NULL != ut)
346 && (NULL != ut->ut_host)
347 && ('\0' != ut->ut_host[0])) {
348 hostname = (char *) xmalloc (sizeof (ut->ut_host) + 1);
349 strncpy (hostname, ut->ut_host, sizeof (ut->ut_host));
350 hostname[sizeof (ut->ut_host)] = '\0';
351 #endif /* HAVE_STRUCT_UTMP_UT_TYPE */
354 if (strncmp(line, "/dev/", 5) == 0) {
358 utxent = (struct utmpx *) xmalloc (sizeof (*utxent));
359 memzero (utxent, sizeof (*utxent));
363 utxent->ut_type = USER_PROCESS;
364 utxent->ut_pid = getpid ();
365 strncpy (utxent->ut_line, line, sizeof (utxent->ut_line));
366 /* existence of ut->ut_id is enforced by configure */
368 strncpy (utxent->ut_id, ut->ut_id, sizeof (utxent->ut_id));
370 /* XXX - assumes /dev/tty?? */
371 strncpy (utxent->ut_id, line + 3, sizeof (utxent->ut_id));
373 #ifdef HAVE_STRUCT_UTMPX_UT_NAME
374 strncpy (utxent->ut_name, name, sizeof (utxent->ut_name));
375 #endif /* HAVE_STRUCT_UTMPX_UT_NAME */
376 strncpy (utxent->ut_user, name, sizeof (utxent->ut_user));
377 if (NULL != hostname) {
378 struct addrinfo *info = NULL;
379 #ifdef HAVE_STRUCT_UTMPX_UT_HOST
380 strncpy (utxent->ut_host, hostname, sizeof (utxent->ut_host));
381 #endif /* HAVE_STRUCT_UTMPX_UT_HOST */
382 #ifdef HAVE_STRUCT_UTMPX_UT_SYSLEN
383 utxent->ut_syslen = MIN (strlen (hostname),
384 sizeof (utxent->ut_host));
385 #endif /* HAVE_STRUCT_UTMPX_UT_SYSLEN */
386 #if defined(HAVE_STRUCT_UTMPX_UT_ADDR) || defined(HAVE_STRUCT_UTMPX_UT_ADDR_V6)
387 if (getaddrinfo (hostname, NULL, NULL, &info) == 0) {
388 /* getaddrinfo might not be reliable.
389 * Just try to log what may be useful.
391 if (info->ai_family == AF_INET) {
392 struct sockaddr_in *sa =
393 (struct sockaddr_in *) info->ai_addr;
394 #ifdef HAVE_STRUCT_UTMPX_UT_ADDR
395 memcpy (utxent->ut_addr,
397 MIN (sizeof (utxent->ut_addr),
398 sizeof (sa->sin_addr)));
399 #endif /* HAVE_STRUCT_UTMPX_UT_ADDR */
400 #ifdef HAVE_STRUCT_UTMPX_UT_ADDR_V6
401 memcpy (utxent->ut_addr_v6,
403 MIN (sizeof (utxent->ut_addr_v6),
404 sizeof (sa->sin_addr)));
405 } else if (info->ai_family == AF_INET6) {
406 struct sockaddr_in6 *sa =
407 (struct sockaddr_in6 *) info->ai_addr;
408 memcpy (utxent->ut_addr_v6,
410 MIN (sizeof (utxent->ut_addr_v6),
411 sizeof (sa->sin6_addr)));
412 #endif /* HAVE_STRUCT_UTMPX_UT_ADDR_V6 */
416 #endif /* HAVE_STRUCT_UTMPX_UT_ADDR || HAVE_STRUCT_UTMPX_UT_ADDR_V6 */
419 /* ut_exit is only for DEAD_PROCESS */
420 utxent->ut_session = getsid (0);
421 if (gettimeofday (&tv, NULL) == 0) {
422 #ifdef HAVE_STRUCT_UTMPX_UT_TIME
423 utxent->ut_time = tv.tv_sec;
424 #endif /* HAVE_STRUCT_UTMPX_UT_TIME */
425 #ifdef HAVE_STRUCT_UTMPX_UT_XTIME
426 utxent->ut_xtime = tv.tv_usec;
427 #endif /* HAVE_STRUCT_UTMPX_UT_XTIME */
428 utxent->ut_tv.tv_sec = tv.tv_sec;
429 utxent->ut_tv.tv_usec = tv.tv_usec;
436 * setutmpx - the UTMPX version for setutmp
438 int setutmpx (struct utmpx *utx)
442 assert (NULL != utx);
445 if (pututxline (utx) == NULL) {
450 updwtmpx (_WTMP_FILE "x", utx);
454 #endif /* USE_UTMPX */