Initial commit for Tizen
[profile/extras/shadow-utils.git] / 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 - 2009, 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 #ifdef USE_UTMPX
41 #include <utmpx.h>
42 #endif
43
44 #include <assert.h>
45 #include <netdb.h>
46 #include <stdio.h>
47
48 #ident "$Id: utmp.c 2834 2009-04-28 20:03:23Z nekral-guest $"
49
50
51 /*
52  * is_my_tty -- determine if "tty" is the same TTY stdin is using
53  */
54 static bool is_my_tty (const char *tty)
55 {
56         /* full_tty shall be at least sizeof utmp.ut_line + 5 */
57         char full_tty[200];
58         /* tmptty shall be bigger than full_tty */
59         static char tmptty[sizeof (full_tty)+1];
60
61         if ('/' != *tty) {
62                 (void) snprintf (full_tty, sizeof full_tty, "/dev/%s", tty);
63                 tty = &full_tty[0];
64         }
65
66         if ('\0' == tmptty[0]) {
67                 const char *tname = ttyname (STDIN_FILENO);
68                 if (NULL != tname) {
69                         (void) strncpy (tmptty, tname, sizeof tmptty);
70                         tmptty[sizeof (tmptty) - 1] = '\0';
71                 }
72         }
73
74         if (NULL == tmptty) {
75                 (void) puts (_("Unable to determine your tty name."));
76                 exit (EXIT_FAILURE);
77         } else if (strncmp (tty, tmptty, sizeof (tmptty)) != 0) {
78                 return false;
79         } else {
80                 return true;
81         }
82 }
83
84 /*
85  * get_current_utmp - return the most probable utmp entry for the current
86  *                    session
87  *
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.
91  *
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.
95  *
96  *      Return NULL if no entries exist in utmp for the current process.
97  */
98 /*@null@*/ /*@only@*/struct utmp *get_current_utmp (void)
99 {
100         struct utmp *ut;
101         struct utmp *ret = NULL;
102
103         setutent ();
104
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])
110 #endif
111 #ifdef HAVE_STRUCT_UTMP_UT_TYPE
112                     && (   (LOGIN_PROCESS == ut->ut_type)
113                         || (USER_PROCESS  == ut->ut_type))
114 #endif
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)) {
118                         break;
119                 }
120         }
121
122         if (NULL != ut) {
123                 ret = (struct utmp *) xmalloc (sizeof (*ret));
124                 memcpy (ret, ut, sizeof (*ret));
125         }
126
127         endutent ();
128
129         return ret;
130 }
131
132 /*
133  * Some systems already have updwtmp() and possibly updwtmpx().  Others
134  * don't, so we re-implement these functions if necessary.
135  */
136 #ifndef HAVE_UPDWTMP
137 static void updwtmp (const char *filename, const struct utmp *ut)
138 {
139         int fd;
140
141         fd = open (filename, O_APPEND | O_WRONLY, 0);
142         if (fd >= 0) {
143                 write (fd, (const char *) ut, sizeof (*ut));
144                 close (fd);
145         }
146 }
147 #endif                          /* ! HAVE_UPDWTMP */
148
149 #ifdef USE_UTMPX
150 #ifndef HAVE_UPDWTMPX
151 static void updwtmpx (const char *filename, const struct utmpx *utx)
152 {
153         int fd;
154
155         fd = open (filename, O_APPEND | O_WRONLY, 0);
156         if (fd >= 0) {
157                 write (fd, (const char *) utx, sizeof (*utx));
158                 close (fd);
159         }
160 }
161 #endif                          /* ! HAVE_UPDWTMPX */
162 #endif                          /* ! USE_UTMPX */
163
164
165 /*
166  * prepare_utmp - prepare an utmp entry so that it can be logged in a
167  *                utmp/wtmp file.
168  *
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
171  *      get_current_utmp
172  *      If ut is NULL, ut_id will be forged based on the line argument.
173  *
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
176  *      exist)
177  *
178  *      Other fields are discarded and filed with new values (if they
179  *      exist).
180  *
181  *      The returned structure shall be freed by the caller.
182  */
183 /*@only@*/struct utmp *prepare_utmp (const char *name,
184                                      const char *line,
185                                      const char *host,
186                                      /*@null@*/const struct utmp *ut)
187 {
188         struct timeval tv;
189         char *hostname = NULL;
190         struct utmp *utent;
191
192         assert (NULL != name);
193         assert (NULL != line);
194
195
196
197         if (   (NULL != host)
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 */
209         }
210
211         if (strncmp(line, "/dev/", 5) == 0) {
212                 line += 5;
213         }
214
215
216         utent = (struct utmp *) xmalloc (sizeof (*utent));
217         memzero (utent, sizeof (*utent));
218
219
220
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
227         if (NULL != ut) {
228                 strncpy (utent->ut_id, ut->ut_id, sizeof (utent->ut_id));
229         } else {
230                 /* XXX - assumes /dev/tty?? */
231                 strncpy (utent->ut_id, line + 3, sizeof (utent->ut_id));
232         }
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.
253                          */
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),
259                                         &(sa->sin_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,
265                                         &(sa->sin_addr),
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,
272                                         &(sa->sin6_addr),
273                                         MIN (sizeof (utent->ut_addr_v6),
274                                              sizeof (sa->sin6_addr)));
275 #endif                          /* HAVE_STRUCT_UTMP_UT_ADDR_V6 */
276                         }
277                         freeaddrinfo (info);
278                 }
279 #endif          /* HAVE_STRUCT_UTMP_UT_ADDR || HAVE_STRUCT_UTMP_UT_ADDR_V6 */
280                 free (hostname);
281         }
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 */
295         }
296
297         return utent;
298 }
299
300 /*
301  * setutmp - Update an entry in utmp and log an entry in wtmp
302  *
303  *      Return 1 on failure and 0 on success.
304  */
305 int setutmp (struct utmp *ut)
306 {
307         int err = 0;
308
309         assert (NULL != ut);
310
311         setutent ();
312         if (pututline (ut) == NULL) {
313                 err = 1;
314         }
315         endutent ();
316
317         updwtmp (_WTMP_FILE, ut);
318
319         return err;
320 }
321
322 #ifdef USE_UTMPX
323 /*
324  * prepare_utmpx - the UTMPX version for prepare_utmp
325  */
326 /*@only@*/struct utmpx *prepare_utmpx (const char *name,
327                                        const char *line,
328                                        const char *host,
329                                        /*@null@*/const struct utmp *ut)
330 {
331         struct timeval tv;
332         char *hostname = NULL;
333         struct utmpx *utxent;
334
335         assert (NULL != name);
336         assert (NULL != line);
337
338
339
340         if (   (NULL != host)
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 */
352         }
353
354         if (strncmp(line, "/dev/", 5) == 0) {
355                 line += 5;
356         }
357
358         utxent = (struct utmpx *) xmalloc (sizeof (*utxent));
359         memzero (utxent, sizeof (*utxent));
360
361
362
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 */
367         if (NULL != ut) {
368                 strncpy (utxent->ut_id, ut->ut_id, sizeof (utxent->ut_id));
369         } else {
370                 /* XXX - assumes /dev/tty?? */
371                 strncpy (utxent->ut_id, line + 3, sizeof (utxent->ut_id));
372         }
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.
390                          */
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,
396                                         &(sa->sin_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,
402                                         &(sa->sin_addr),
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,
409                                         &(sa->sin6_addr),
410                                         MIN (sizeof (utxent->ut_addr_v6),
411                                              sizeof (sa->sin6_addr)));
412 #endif                          /* HAVE_STRUCT_UTMPX_UT_ADDR_V6 */
413                         }
414                         freeaddrinfo (info);
415                 }
416 #endif          /* HAVE_STRUCT_UTMPX_UT_ADDR || HAVE_STRUCT_UTMPX_UT_ADDR_V6 */
417                 free (hostname);
418         }
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;
430         }
431
432         return utxent;
433 }
434
435 /*
436  * setutmpx - the UTMPX version for setutmp
437  */
438 int setutmpx (struct utmpx *utx)
439 {
440         int err = 0;
441
442         assert (NULL != utx);
443
444         setutxent ();
445         if (pututxline (utx) == NULL) {
446                 err = 1;
447         }
448         endutxent ();
449
450         updwtmpx (_WTMP_FILE "x", utx);
451
452         return err;
453 }
454 #endif                          /* USE_UTMPX */
455