busybox/libbb/utmp.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * utmp/wtmp support routines.
   4 *
   5 * Copyright (C) 2010 Denys Vlasenko
   6 *
   7 * Licensed under GPLv2, see file LICENSE in this source tree.
   8 */
   9#include "libbb.h"
  10
  11static void touch(const char *filename)
  12{
  13        if (access(filename, R_OK | W_OK) == -1)
  14                close(open(filename, O_WRONLY | O_CREAT, 0664));
  15}
  16
  17void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname)
  18{
  19        struct utmpx utent;
  20        char *id;
  21        unsigned width;
  22
  23        memset(&utent, 0, sizeof(utent));
  24        utent.ut_pid = pid;
  25        utent.ut_type = new_type;
  26        tty_name = skip_dev_pfx(tty_name);
  27        safe_strncpy(utent.ut_line, tty_name, sizeof(utent.ut_line));
  28        if (username)
  29                safe_strncpy(utent.ut_user, username, sizeof(utent.ut_user));
  30        if (hostname)
  31                safe_strncpy(utent.ut_host, hostname, sizeof(utent.ut_host));
  32        utent.ut_tv.tv_sec = time(NULL);
  33
  34        /* Invent our own ut_id. ut_id is only 4 chars wide.
  35         * Try to fit something remotely meaningful... */
  36        id = utent.ut_id;
  37        width = sizeof(utent.ut_id);
  38        if (tty_name[0] == 'p') {
  39                /* if "ptyXXX", map to "pXXX" */
  40                /* if "pts/XX", map to "p/XX" */
  41                *id++ = 'p';
  42                width--;
  43        } /* else: usually it's "ttyXXXX", map to "XXXX" */
  44        if (strlen(tty_name) > 3)
  45                tty_name += 3;
  46        strncpy(id, tty_name, width);
  47
  48        touch(_PATH_UTMPX);
  49        //utmpxname(_PATH_UTMPX);
  50        setutxent();
  51        /* Append new one (hopefully, unless we collide on ut_id) */
  52        pututxline(&utent);
  53        endutxent();
  54
  55#if ENABLE_FEATURE_WTMP
  56        /* "man utmp" says wtmp file should *not* be created automagically */
  57        /*touch(bb_path_wtmp_file);*/
  58        updwtmpx(bb_path_wtmp_file, &utent);
  59#endif
  60}
  61
  62/*
  63 * Read "man utmp" to make sense out of it.
  64 */
  65void FAST_FUNC update_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname)
  66{
  67        struct utmpx utent;
  68        struct utmpx *utp;
  69
  70        touch(_PATH_UTMPX);
  71        //utmpxname(_PATH_UTMPX);
  72        setutxent();
  73
  74        /* Did init/getty/telnetd/sshd/... create an entry for us?
  75         * It should be (new_type-1), but we'd also reuse
  76         * any other potentially stale xxx_PROCESS entry */
  77        while ((utp = getutxent()) != NULL) {
  78                if (utp->ut_pid == pid
  79                // && ut->ut_line[0]
  80                 && utp->ut_id[0] /* must have nonzero id */
  81                 && (  utp->ut_type == INIT_PROCESS
  82                    || utp->ut_type == LOGIN_PROCESS
  83                    || utp->ut_type == USER_PROCESS
  84                    || utp->ut_type == DEAD_PROCESS
  85                    )
  86                ) {
  87                        if (utp->ut_type >= new_type) {
  88                                /* Stale record. Nuke hostname */
  89                                memset(utp->ut_host, 0, sizeof(utp->ut_host));
  90                        }
  91                        /* NB: pututxline (see later) searches for matching utxent
  92                         * using getutxid(utent) - we must not change ut_id
  93                         * if we want *exactly this* record to be overwritten!
  94                         */
  95                        break;
  96                }
  97        }
  98        //endutxent(); - no need, pututxline can deal with (and actually likes)
  99        //the situation when utmp file is positioned on found record
 100
 101        if (!utp) {
 102                if (new_type != DEAD_PROCESS)
 103                        write_new_utmp(pid, new_type, tty_name, username, hostname);
 104                else
 105                        endutxent();
 106                return;
 107        }
 108
 109        /* Make a copy. We can't use *utp, pututxline's internal getutxid
 110         * will overwrite it before it is used! */
 111        utent = *utp;
 112
 113        utent.ut_type = new_type;
 114        if (tty_name)
 115                safe_strncpy(utent.ut_line, skip_dev_pfx(tty_name), sizeof(utent.ut_line));
 116        if (username)
 117                safe_strncpy(utent.ut_user, username, sizeof(utent.ut_user));
 118        if (hostname)
 119                safe_strncpy(utent.ut_host, hostname, sizeof(utent.ut_host));
 120        utent.ut_tv.tv_sec = time(NULL);
 121
 122        /* Update, or append new one */
 123        //setutxent();
 124        pututxline(&utent);
 125        endutxent();
 126
 127#if ENABLE_FEATURE_WTMP
 128        /* "man utmp" says wtmp file should *not* be created automagically */
 129        /*touch(bb_path_wtmp_file);*/
 130        updwtmpx(bb_path_wtmp_file, &utent);
 131#endif
 132}
 133
 134/* man utmp:
 135 * When init(8) finds that a process has exited, it locates its utmp entry
 136 * by ut_pid, sets ut_type to DEAD_PROCESS, and clears ut_user, ut_host
 137 * and ut_time with null bytes.
 138 * [same applies to other processes which maintain utmp entries, like telnetd]
 139 *
 140 * We do not bother actually clearing fields:
 141 * it might be interesting to know who was logged in and from where
 142 */
 143void FAST_FUNC update_utmp_DEAD_PROCESS(pid_t pid)
 144{
 145        update_utmp(pid, DEAD_PROCESS, NULL, NULL, NULL);
 146}
 147