/* xdmutmp: add utmp entries for xdm clients $Id: xdmutmp.c,v 1.4 1997/04/02 14:13:17 tjchol01 Exp $ Author: Tomasz J. Cholewo (t.cholewo@ieee.org) */ #include #include /* memset */ #include /* malloc */ #include /* getopt */ #include /* open, write */ #include /* time */ #include /* getpwnam */ #include #include #include #include #define PROGNAME "xdmutmp" /* size of |utmpx.ut_id| */ #define ID_LEN 4 /* Has to end with a slash! */ #define LASTLOG_DIR "/var/adm/lastlog/" /* Must be at least length of |LASTLOG_DIR| and the longest |user_name|. */ #define LLOG_LEN 100 #ifdef DEBUG #undef UTMP_FILE #define UTMP_FILE "./utmp" #undef WTMP_FILE #define WTMP_FILE "./wtmp" #undef UTMPX_FILE #define UTMPX_FILE "./utmpx" #undef WTMPX_FILE #define WTMPX_FILE "./wtmpx" #undef LASTLOG_DIR #define LASTLOG_DIR "./lastlog/" #endif int min (int a, int b) { return (a < b) ? a : b; } /* |line| field is constructed by primitive hashing of host name and representing it in "base64" encoding. */ char * hash_id (const char *host) { static char id[ID_LEN + 1]; const char *p; int i, h = 0; for (p = host; *p; p++) h = (256 * h + *p) % 104729; /* 64^3 = 262144 */ for (i = 0; i < ID_LEN - 1; i++) { id[i] = (h % 64) + 32; h /= 64; } id[ID_LEN] = '\0'; return id; } int main (int argc, const char **argv) { /* options and arguments */ int dflag; const char *user_name; const char *host_name; struct utmp utmp_entry; /* For |sizeof| only */ struct utmpx utmpx_entry; struct passwd *pwd; const char *id; char llog_name[LLOG_LEN]; int llog; openlog (PROGNAME, LOG_PERROR, LOG_USER); if (argc < 4 || argv[1][0] != '-') { syslog (LOG_INFO, "Usage: " PROGNAME " -a|-d user display"); return 1; } switch (argv[1][1]) { case 'a': dflag = 0; break; case 'd': dflag = 1; break; default: syslog (LOG_ERR, "Bad option `%c'", argv[1][1]); return 1; } user_name = argv[2]; host_name = argv[3]; /* |user_name| must exist in /etc/passwd. */ if (!(pwd = getpwnam (user_name))) { syslog (LOG_ERR, "User `%s' unknown", user_name); return 1; } /* Initialize utmp/utmpx records. */ memset (&utmpx_entry, 0, sizeof (utmpx_entry)); /* Fill in the appropriate records of the utmpx entry. */ strncpy (utmpx_entry.ut_user, user_name, sizeof (utmpx_entry.ut_user)); utmpx_entry.ut_pid = getppid (); id = hash_id (host_name); strncpy (utmpx_entry.ut_id, id, sizeof (utmpx_entry.ut_id)); /* `who' expects that |ut_line| is null-terminated at utmp (!) size. */ strncpy (utmpx_entry.ut_line, host_name, sizeof (utmp_entry.ut_line) - 1); utmpx_entry.ut_type = dflag ? DEAD_PROCESS : USER_PROCESS; utmpx_entry.ut_syslen = min (strlen (host_name) + 1, sizeof (utmpx_entry.ut_host)); strncpy (utmpx_entry.ut_host, host_name, utmpx_entry.ut_syslen); time (&utmpx_entry.ut_tv.tv_sec); /* It is not documented but |pututxline| modifies both utmp and utmpx. */ #ifdef DEBUG utmpxname (UTMPX_FILE); #endif setutxent (); getutxid (&utmpx_entry); if (!pututxline (&utmpx_entry)) syslog (LOG_ERR, "%s: %m", UTMP_FILE); endutxent (); /* Append analogous entries to wtmp and wtmpx. */ updwtmpx (WTMPX_FILE, &utmpx_entry); /* Modify user's lastlog file. */ if (!dflag) { strcpy (llog_name, LASTLOG_DIR); strcat (llog_name, user_name); llog = open (llog_name, O_WRONLY | O_CREAT, 0644); if (llog != -1) { struct lastlog ll; memset ((char *) &ll, 0, sizeof (ll)); ll.ll_time = utmpx_entry.ut_tv.tv_sec; strncpy (ll.ll_host, host_name, sizeof (ll.ll_host)); /* Using |write| tries to avoid race conditions (?). */ if (write (llog, (char *) &ll, sizeof (ll)) != sizeof (ll)) syslog (LOG_ERR, "%s: %m", llog_name); close (llog); } else syslog (LOG_ERR, "%s: %m", llog_name); } return 0; }