1a6d9b409Smrg/* 2a6d9b409Smrg * Copyright 1990, 1998 The Open Group 3a6d9b409Smrg * 4a6d9b409Smrg * Permission to use, copy, modify, distribute, and sell this software and its 5a6d9b409Smrg * documentation for any purpose is hereby granted without fee, provided that 6a6d9b409Smrg * the above copyright notice appear in all copies and that both that 7a6d9b409Smrg * copyright notice and this permission notice appear in supporting 8a6d9b409Smrg * documentation. 9a097bd00Smrg * 10a6d9b409Smrg * The above copyright notice and this permission notice shall be included 11a6d9b409Smrg * in all copies or substantial portions of the Software. 12a097bd00Smrg * 13a6d9b409Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 14a6d9b409Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 15a6d9b409Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 16a6d9b409Smrg * IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 17a6d9b409Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 18a6d9b409Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 19a6d9b409Smrg * OTHER DEALINGS IN THE SOFTWARE. 20a097bd00Smrg * 21a6d9b409Smrg * Except as contained in this notice, the name of The Open Group shall 22a6d9b409Smrg * not be used in advertising or otherwise to promote the sale, use or 23a6d9b409Smrg * other dealings in this Software without prior written authorization 24a6d9b409Smrg * from The Open Group. 25a6d9b409Smrg * 26a6d9b409Smrg */ 27a6d9b409Smrg 28a097bd00Smrg/* 29838f5b0bSmrg * Copyright (c) 2005, Oracle and/or its affiliates. 30a6d9b409Smrg * 31a6d9b409Smrg * Permission is hereby granted, free of charge, to any person obtaining a 321e5fa1c5Smrg * copy of this software and associated documentation files (the "Software"), 331e5fa1c5Smrg * to deal in the Software without restriction, including without limitation 341e5fa1c5Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 351e5fa1c5Smrg * and/or sell copies of the Software, and to permit persons to whom the 361e5fa1c5Smrg * Software is furnished to do so, subject to the following conditions: 371e5fa1c5Smrg * 381e5fa1c5Smrg * The above copyright notice and this permission notice (including the next 391e5fa1c5Smrg * paragraph) shall be included in all copies or substantial portions of the 401e5fa1c5Smrg * Software. 411e5fa1c5Smrg * 421e5fa1c5Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 431e5fa1c5Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 441e5fa1c5Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 451e5fa1c5Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 461e5fa1c5Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 471e5fa1c5Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 481e5fa1c5Smrg * DEALINGS IN THE SOFTWARE. 49a6d9b409Smrg */ 50a6d9b409Smrg 51a6d9b409Smrg/* 52a6d9b409Smrg * Author: Keith Packard, MIT X Consortium 53a6d9b409Smrg * Lastlog support and dynamic utmp entry allocation 54a6d9b409Smrg * by Andreas Stolcke <stolcke@icsi.berkeley.edu> 55a6d9b409Smrg */ 56a6d9b409Smrg 57a6d9b409Smrg/* 58a6d9b409Smrg * sessreg 59a6d9b409Smrg * 60a6d9b409Smrg * simple wtmp/utmp frobber 61a6d9b409Smrg * 62a6d9b409Smrg * usage: sessreg [ -w <wtmp-file> ] [ -u <utmp-file> ] 63a6d9b409Smrg * [ -l <line> ] 64a097bd00Smrg * [ -L <lastlog-file> ] / #ifdef USE_LASTLOG 65a6d9b409Smrg * [ -h <host-name> ] / BSD only 66a6d9b409Smrg * [ -s <slot-number> ] [ -x Xservers-file ] / BSD only 67a6d9b409Smrg * [ -t <ttys-file> ] / BSD only 68a097bd00Smrg * [ -a ] [ -d ] user-name 69a6d9b409Smrg * 70a6d9b409Smrg * one of -a or -d must be specified 71a6d9b409Smrg */ 72a6d9b409Smrg 73a6d9b409Smrg#include "sessreg.h" 74a6d9b409Smrg 75a097bd00Smrg#include <X11/Xos.h> 76a097bd00Smrg#include <X11/Xfuncs.h> 77b91640d3Smrg#include <X11/Xfuncproto.h> 78a097bd00Smrg#include <stdio.h> 79a097bd00Smrg#include <stdlib.h> 80a6d9b409Smrg#include <time.h> 81a6d9b409Smrg 821e5fa1c5Smrg#ifdef USE_UTMP 831e5fa1c5Smrgstatic void set_utmp (struct utmp *u, char *line, char *user, char *host, 84a097bd00Smrg time_t date, int addp); 851e5fa1c5Smrg#endif 86a6d9b409Smrg 87a6d9b409Smrg#ifdef USE_UTMPX 88a6d9b409Smrgstatic void set_utmpx (struct utmpx *u, const char *line, const char *user, 89a097bd00Smrg const char *host, time_t date, int addp); 90a6d9b409Smrg#endif 91a6d9b409Smrg 92efda2da8Smrgstatic int wflag, uflag, lflag; 93a097bd00Smrgstatic const char *wtmp_file, *utmp_file; 94a6d9b409Smrg#ifdef USE_UTMPX 951e5fa1c5Smrg#ifdef HAVE_UPDWTMPX 96a097bd00Smrgstatic const char *wtmpx_file = NULL; 971e5fa1c5Smrg#endif 981e5fa1c5Smrg#ifdef HAVE_UTMPXNAME 99a097bd00Smrgstatic const char *utmpx_file = NULL; 1001e5fa1c5Smrg#endif 101a6d9b409Smrg#endif 102a097bd00Smrg 103efda2da8Smrgstatic int utmp_none, wtmp_none; 104a6d9b409Smrg/* 105a6d9b409Smrg * BSD specific variables. To make life much easier for Xstartup/Xreset 106a6d9b409Smrg * maintainers, these arguments are accepted but ignored for sysV 107a6d9b409Smrg */ 108a097bd00Smrgstatic int hflag, xflag, tflag; 109efda2da8Smrgstatic char *host_name = NULL; 110a097bd00Smrg#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE) 111a097bd00Smrgstatic int sflag; 112efda2da8Smrgstatic int slot_number; 1131e5fa1c5Smrg#endif 114efda2da8Smrgstatic char *xservers_file, *ttys_file; 115efda2da8Smrgstatic char *user_name; 116efda2da8Smrgstatic int aflag, dflag; 117a097bd00Smrg#ifdef USE_LASTLOG 118a097bd00Smrgstatic const char *llog_file; 119efda2da8Smrgstatic int llog_none, Lflag; 120a6d9b409Smrg#endif 121a6d9b409Smrg 122efda2da8Smrgstatic char *program_name; 123a6d9b409Smrg 124a097bd00Smrg#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE) 125a6d9b409Smrgstatic int findslot (char *line_name, char *host_name, int addp, int slot); 126a6d9b409Smrgstatic int Xslot (char *ttys_file, char *servers_file, char *tty_line, 127a6d9b409Smrg char *host_name, int addp); 128a6d9b409Smrg#endif 129a6d9b409Smrg 130b91640d3Smrgstatic void _X_NORETURN _X_COLD 131a6d9b409Smrgusage (int x) 132a6d9b409Smrg{ 133b91640d3Smrg fprintf (stderr, 134b91640d3Smrg "%s: usage %s {-a -d} [-w wtmp-file] [-u utmp-file]" 135a097bd00Smrg#ifdef USE_LASTLOG 136b91640d3Smrg " [-L lastlog-file]" 137a6d9b409Smrg#endif 138b91640d3Smrg "\n" 139b91640d3Smrg " [-t ttys-file] [-l line-name] [-h host-name] [-V]\n" 140b91640d3Smrg " [-s slot-number] [-x servers-file] user-name\n", 141b91640d3Smrg program_name, program_name); 142b91640d3Smrg exit (x); 143a6d9b409Smrg} 144a6d9b409Smrg 145a6d9b409Smrgstatic char * 146a6d9b409Smrggetstring (char ***avp, int *flagp) 147a6d9b409Smrg{ 148a6d9b409Smrg char **a = *avp; 149b91640d3Smrg char *flag = *a; 150a6d9b409Smrg 151b91640d3Smrg if (*flagp != 0) { 152b91640d3Smrg fprintf (stderr, "%s: cannot give more than one -%s option\n", 153b91640d3Smrg program_name, flag); 154b91640d3Smrg usage (1); 155b91640d3Smrg } 156b91640d3Smrg *flagp = 1; 157b91640d3Smrg /* if the argument is given immediately following the flag, 158b91640d3Smrg i.e. "sessreg -hfoo ...", not "sessreg -h foo ...", 159b91640d3Smrg then return the rest of the string as the argument value */ 160a6d9b409Smrg if (*++*a) 161a6d9b409Smrg return *a; 162b91640d3Smrg /* else use the next pointer in the argv list as the argument value */ 163a6d9b409Smrg ++a; 164b91640d3Smrg if (!*a) { 165b91640d3Smrg fprintf (stderr, "%s: -%s requires an argument\n", 166b91640d3Smrg program_name, flag); 167b91640d3Smrg usage (1); 168b91640d3Smrg } 169a6d9b409Smrg *avp = a; 170a6d9b409Smrg return *a; 171a6d9b409Smrg} 172a6d9b409Smrg 173a097bd00Smrg#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE) 174a6d9b409Smrgstatic int 175a6d9b409Smrgsyserr (int x, const char *s) 176a6d9b409Smrg{ 177a6d9b409Smrg if (x == -1) { 178a6d9b409Smrg perror (s); 179a6d9b409Smrg exit (1); 180a6d9b409Smrg } 181a6d9b409Smrg return x; 182a6d9b409Smrg} 183a6d9b409Smrg#endif 184a6d9b409Smrg 185a6d9b409Smrgstatic int 186a6d9b409Smrgsysnerr (int x, const char *s) 187a6d9b409Smrg{ 188a6d9b409Smrg if (x == 0) { 189a6d9b409Smrg perror (s); 190a6d9b409Smrg exit (1); 191a6d9b409Smrg } 192a6d9b409Smrg return x; 193a6d9b409Smrg} 194a6d9b409Smrg 1958b8e729cSmrg/* 1968b8e729cSmrg * While this looks like it could be replaced with strlcpy() on platforms 1978b8e729cSmrg * that have it, we're sticking with strncpy() so that we zero out the 1988b8e729cSmrg * whole buffer to avoid writing garbage to the fixed length fields in the 1998b8e729cSmrg * utmp/wtmp files, since strlcpy() does not write past the \0 terminator. 2008b8e729cSmrg */ 2018b8e729cSmrgstatic void 2028b8e729cSmrgsafe_strncpy(char *dest, const char *src, size_t n) 2038b8e729cSmrg{ 20492e95ad1Smrg if (n > 0) { 20592e95ad1Smrg strncpy(dest, src, n - 1); 2068b8e729cSmrg dest[n - 1] = '\0'; 20792e95ad1Smrg } 2088b8e729cSmrg} 2098b8e729cSmrg 210a6d9b409Smrgint 211a6d9b409Smrgmain (int argc, char **argv) 212a6d9b409Smrg{ 213a097bd00Smrg#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE) 214a6d9b409Smrg int utmp; 215a6d9b409Smrg#endif 216a097bd00Smrg#ifndef USE_UTMPX 217a6d9b409Smrg int wtmp; 218a097bd00Smrg#endif 219a097bd00Smrg time_t current_time; 2201e5fa1c5Smrg#ifdef USE_UTMP 221a6d9b409Smrg struct utmp utmp_entry; 2221e5fa1c5Smrg#endif 223a6d9b409Smrg#ifdef USE_UTMPX 224a6d9b409Smrg struct utmpx utmpx_entry; 225a6d9b409Smrg#endif 226a097bd00Smrg char * line = NULL; 227a6d9b409Smrg 228a6d9b409Smrg program_name = argv[0]; 229a6d9b409Smrg while (*++argv && **argv == '-') { 230a6d9b409Smrg switch (*++*argv) { 231a6d9b409Smrg case 'w': 232a6d9b409Smrg wtmp_file = getstring (&argv, &wflag); 233a6d9b409Smrg if (!strcmp (wtmp_file, "none")) 234a6d9b409Smrg wtmp_none = 1; 235b91640d3Smrg#if defined(USE_UTMPX) && defined(HAVE_UPDWTMPX) 236b91640d3Smrg else 237b91640d3Smrg wtmpx_file = wtmp_file; 238b91640d3Smrg#endif 239a6d9b409Smrg break; 240a6d9b409Smrg case 'u': 241a6d9b409Smrg utmp_file = getstring (&argv, &uflag); 242a6d9b409Smrg if (!strcmp (utmp_file, "none")) 243a6d9b409Smrg utmp_none = 1; 244b91640d3Smrg#if defined(USE_UTMPX) && defined(HAVE_UTMPXNAME) 245b91640d3Smrg else 246b91640d3Smrg utmpx_file = utmp_file; 247b91640d3Smrg#endif 248a6d9b409Smrg break; 249a097bd00Smrg#ifdef USE_LASTLOG 250a6d9b409Smrg case 'L': 251a6d9b409Smrg llog_file = getstring (&argv, &Lflag); 252a6d9b409Smrg if (!strcmp (llog_file, "none")) 253a6d9b409Smrg llog_none = 1; 254a6d9b409Smrg break; 255a6d9b409Smrg#endif 256a6d9b409Smrg case 't': 257a6d9b409Smrg ttys_file = getstring (&argv, &tflag); 258a6d9b409Smrg break; 259a6d9b409Smrg case 'l': 260a6d9b409Smrg line = getstring (&argv, &lflag); 261a6d9b409Smrg break; 262a6d9b409Smrg case 'h': 263a6d9b409Smrg host_name = getstring (&argv, &hflag); 264a6d9b409Smrg break; 265a6d9b409Smrg case 's': 266a097bd00Smrg#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE) 267a6d9b409Smrg slot_number = atoi (getstring (&argv, &sflag)); 2681e5fa1c5Smrg#endif 269a6d9b409Smrg break; 270a6d9b409Smrg case 'x': 271a6d9b409Smrg xservers_file = getstring (&argv, &xflag); 272a6d9b409Smrg break; 273a6d9b409Smrg case 'a': 274a6d9b409Smrg aflag++; 275a6d9b409Smrg break; 276a6d9b409Smrg case 'd': 277a6d9b409Smrg dflag++; 278a6d9b409Smrg break; 279a097bd00Smrg case 'V': 280838f5b0bSmrg puts(PACKAGE_STRING); 281a097bd00Smrg exit (0); 282838f5b0bSmrg case '-': 283838f5b0bSmrg if (strcmp(*argv, "-help") == 0) { 284838f5b0bSmrg usage (0); 285838f5b0bSmrg } 286838f5b0bSmrg if (strcmp(*argv, "-version") == 0) { 287838f5b0bSmrg puts (PACKAGE_STRING); 288838f5b0bSmrg exit (0); 289838f5b0bSmrg } 290838f5b0bSmrg /* fallthrough */ 291a6d9b409Smrg default: 292838f5b0bSmrg fprintf (stderr, "%s: unrecognized option '-%s'\n", 293b91640d3Smrg program_name, argv[0]); 294a6d9b409Smrg usage (1); 295a6d9b409Smrg } 296a6d9b409Smrg } 297b91640d3Smrg user_name = *argv++; 298b91640d3Smrg if (user_name == NULL) { 299b91640d3Smrg fprintf (stderr, "%s: missing required user-name argument\n", 300b91640d3Smrg program_name); 301b91640d3Smrg usage (1); 302b91640d3Smrg } 303b91640d3Smrg if (*argv != NULL) { 304b91640d3Smrg fprintf (stderr, "%s: unrecognized argument '%s'\n", 305b91640d3Smrg program_name, argv[0]); 306b91640d3Smrg usage (1); 307b91640d3Smrg } 308a6d9b409Smrg /* 309a6d9b409Smrg * complain if neither aflag nor dflag are set, 310a6d9b409Smrg * or if both are set. 311a6d9b409Smrg */ 312b91640d3Smrg if (!(aflag ^ dflag)) { 313b91640d3Smrg fprintf (stderr, "%s: must specify exactly one of -a or -d\n", 314b91640d3Smrg program_name); 315b91640d3Smrg usage (1); 316b91640d3Smrg } 317b91640d3Smrg if (xflag && !lflag) { 318b91640d3Smrg fprintf (stderr, "%s: must specify -l when -x is used\n", 319b91640d3Smrg program_name); 320b91640d3Smrg usage (1); 321b91640d3Smrg } 322a6d9b409Smrg /* set up default file names */ 323a6d9b409Smrg if (!wflag) { 324a6d9b409Smrg wtmp_file = WTMP_FILE; 3251e5fa1c5Smrg#if defined(USE_UTMPX) && defined(HAVE_UPDWTMPX) 326a6d9b409Smrg wtmpx_file = WTMPX_FILE; 327a6d9b409Smrg#endif 328a6d9b409Smrg } 329a6d9b409Smrg if (!uflag) { 330a6d9b409Smrg utmp_file = UTMP_FILE; 3311e5fa1c5Smrg#if defined(USE_UTMPX) && defined(HAVE_UTMPXNAME) 332a6d9b409Smrg utmpx_file = UTMPX_FILE; 333a6d9b409Smrg#endif 334a6d9b409Smrg } 335a097bd00Smrg#ifdef USE_LASTLOG 336a6d9b409Smrg if (!Lflag) 337a6d9b409Smrg llog_file = LLOG_FILE; 338a6d9b409Smrg#endif 339a097bd00Smrg#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE) 340a6d9b409Smrg if (!tflag) 341a6d9b409Smrg ttys_file = TTYS_FILE; 342a6d9b409Smrg if (!sflag && !utmp_none) { 343a6d9b409Smrg if (xflag) 344a6d9b409Smrg sysnerr (slot_number = Xslot (ttys_file, xservers_file, line, host_name, aflag), "Xslot"); 345a6d9b409Smrg else 346a6d9b409Smrg sysnerr (slot_number = ttyslot (), "ttyslot"); 347a6d9b409Smrg } 348a6d9b409Smrg#endif 349a6d9b409Smrg if (!lflag) { 350a097bd00Smrg sysnerr ((line = ttyname (0)) != NULL, "ttyname"); 351a097bd00Smrg if (strncmp(line, "/dev/", 5) == 0) 352a097bd00Smrg line += 5; 353a6d9b409Smrg } 354a6d9b409Smrg time (¤t_time); 3551e5fa1c5Smrg#ifdef USE_UTMP 356a6d9b409Smrg set_utmp (&utmp_entry, line, user_name, host_name, current_time, aflag); 3571e5fa1c5Smrg#endif 358a6d9b409Smrg 359a6d9b409Smrg#ifdef USE_UTMPX 360a6d9b409Smrg /* need to set utmpxname() before calling set_utmpx() for 361a6d9b409Smrg UtmpxIdOpen to work */ 3621e5fa1c5Smrg# ifdef HAVE_UTMPXNAME 363a6d9b409Smrg if (utmpx_file != NULL) { 364a097bd00Smrg utmpxname (utmpx_file); 365a6d9b409Smrg } 3661e5fa1c5Smrg# endif 367a6d9b409Smrg set_utmpx (&utmpx_entry, line, user_name, 368a6d9b409Smrg host_name, current_time, aflag); 369a097bd00Smrg#endif 370a6d9b409Smrg 371a6d9b409Smrg if (!utmp_none) { 372a6d9b409Smrg#ifdef USE_UTMPX 373a097bd00Smrg# ifdef HAVE_UTMPXNAME 374a097bd00Smrg if (utmpx_file != NULL) 3751e5fa1c5Smrg# endif 376a097bd00Smrg { 377a097bd00Smrg setutxent (); 378a097bd00Smrg (void) getutxid (&utmpx_entry); 379a097bd00Smrg pututxline (&utmpx_entry); 380a097bd00Smrg endutxent (); 381a097bd00Smrg } 382a6d9b409Smrg#endif 3831e5fa1c5Smrg#ifdef USE_UTMP 384a097bd00Smrg# ifdef HAVE_PUTUTLINE 385a6d9b409Smrg utmpname (utmp_file); 386a6d9b409Smrg setutent (); 387a6d9b409Smrg (void) getutid (&utmp_entry); 388a6d9b409Smrg pututline (&utmp_entry); 389a6d9b409Smrg endutent (); 3901e5fa1c5Smrg# else 391a6d9b409Smrg utmp = open (utmp_file, O_RDWR); 392a6d9b409Smrg if (utmp != -1) { 39311a95ff3Smrg syserr ((int) lseek (utmp, (off_t) slot_number * sizeof (struct utmp), 0), "lseek"); 394a6d9b409Smrg sysnerr (write (utmp, (char *) &utmp_entry, sizeof (utmp_entry)) 395a097bd00Smrg == sizeof (utmp_entry), "write utmp entry"); 396a6d9b409Smrg close (utmp); 397a6d9b409Smrg } 3981e5fa1c5Smrg# endif 3991e5fa1c5Smrg#endif /* USE_UTMP */ 400a6d9b409Smrg } 401a6d9b409Smrg if (!wtmp_none) { 402a6d9b409Smrg#ifdef USE_UTMPX 4031e5fa1c5Smrg# ifdef HAVE_UPDWTMPX 404a6d9b409Smrg if (wtmpx_file != NULL) { 405a6d9b409Smrg updwtmpx(wtmpx_file, &utmpx_entry); 406a6d9b409Smrg } 4071e5fa1c5Smrg# endif 408a6d9b409Smrg#else 409a6d9b409Smrg wtmp = open (wtmp_file, O_WRONLY|O_APPEND); 410a6d9b409Smrg if (wtmp != -1) { 411a6d9b409Smrg sysnerr (write (wtmp, (char *) &utmp_entry, sizeof (utmp_entry)) 412a097bd00Smrg == sizeof (utmp_entry), "write wtmp entry"); 413a6d9b409Smrg close (wtmp); 414a6d9b409Smrg } 415a097bd00Smrg#endif 416a6d9b409Smrg } 417a097bd00Smrg#ifdef USE_LASTLOG 418a6d9b409Smrg if (aflag && !llog_none) { 419a097bd00Smrg int llog; 420a097bd00Smrg struct passwd *pwd = getpwnam(user_name); 421a6d9b409Smrg 422a097bd00Smrg sysnerr( pwd != NULL, "get user id"); 423a097bd00Smrg llog = open (llog_file, O_RDWR); 424a6d9b409Smrg 425a6d9b409Smrg if (llog != -1) { 426a6d9b409Smrg struct lastlog ll; 427a6d9b409Smrg 42811a95ff3Smrg sysnerr (lseek(llog, (off_t) (pwd->pw_uid*sizeof(ll)), 0) 429a097bd00Smrg != -1, "seeking lastlog entry"); 430a097bd00Smrg memset(&ll, 0, sizeof(ll)); 431a6d9b409Smrg ll.ll_time = current_time; 432a6d9b409Smrg if (line) 4338b8e729cSmrg safe_strncpy (ll.ll_line, line, sizeof (ll.ll_line)); 434a6d9b409Smrg if (host_name) 4358b8e729cSmrg safe_strncpy (ll.ll_host, host_name, sizeof (ll.ll_host)); 436a6d9b409Smrg 437a6d9b409Smrg sysnerr (write (llog, (char *) &ll, sizeof (ll)) 438a097bd00Smrg == sizeof (ll), "write lastlog entry"); 439a6d9b409Smrg close (llog); 440a6d9b409Smrg } 441a6d9b409Smrg } 442a6d9b409Smrg#endif 443a6d9b409Smrg return 0; 444a6d9b409Smrg} 445a6d9b409Smrg 446a6d9b409Smrg/* 447a6d9b409Smrg * fill in the appropriate records of the utmp entry 448a6d9b409Smrg */ 449a6d9b409Smrg 4501e5fa1c5Smrg#ifdef USE_UTMP 451a6d9b409Smrgstatic void 452a097bd00Smrgset_utmp (struct utmp *u, char *line, char *user, char *host, time_t date, int addp) 453a6d9b409Smrg{ 454a097bd00Smrg memset (u, 0, sizeof (*u)); 455a6d9b409Smrg if (line) 4568b8e729cSmrg safe_strncpy (u->ut_line, line, sizeof (u->ut_line)); 457a6d9b409Smrg else 458a097bd00Smrg memset (u->ut_line, 0, sizeof (u->ut_line)); 459a6d9b409Smrg if (addp && user) 4608b8e729cSmrg safe_strncpy (u->ut_name, user, sizeof (u->ut_name)); 461a6d9b409Smrg else 462a097bd00Smrg memset (u->ut_name, 0, sizeof (u->ut_name)); 463a097bd00Smrg#ifdef HAVE_STRUCT_UTMP_UT_ID 464a6d9b409Smrg if (line) { 465a097bd00Smrg size_t i; 466a6d9b409Smrg /* 467a6d9b409Smrg * this is a bit crufty, but 468a6d9b409Smrg * follows the apparent conventions in 469a6d9b409Smrg * the ttys file. ut_id is only 4 bytes 470a6d9b409Smrg * long, and the last 4 bytes of the line 471a6d9b409Smrg * name are written into it, left justified. 472a6d9b409Smrg */ 473a6d9b409Smrg i = strlen (line); 474a6d9b409Smrg if (i >= sizeof (u->ut_id)) 475a6d9b409Smrg i -= sizeof (u->ut_id); 476a6d9b409Smrg else 477a6d9b409Smrg i = 0; 4788b8e729cSmrg safe_strncpy (u->ut_id, line + i, sizeof (u->ut_id)); 479a6d9b409Smrg } else 480a097bd00Smrg memset (u->ut_id, 0, sizeof (u->ut_id)); 481a097bd00Smrg#endif 482a097bd00Smrg#ifdef HAVE_STRUCT_UTMP_UT_PID 483a097bd00Smrg if (addp) 484a6d9b409Smrg u->ut_pid = getppid (); 485a097bd00Smrg else 486a6d9b409Smrg u->ut_pid = 0; 487a097bd00Smrg#endif 488a097bd00Smrg#ifdef HAVE_STRUCT_UTMP_UT_TYPE 489a097bd00Smrg if (addp) 490a097bd00Smrg u->ut_type = USER_PROCESS; 491a097bd00Smrg else 492a6d9b409Smrg u->ut_type = DEAD_PROCESS; 493a6d9b409Smrg#endif 494a097bd00Smrg#ifdef HAVE_STRUCT_UTMP_UT_HOST 495a6d9b409Smrg if (addp && host) 4968b8e729cSmrg safe_strncpy (u->ut_host, host, sizeof (u->ut_host)); 497a6d9b409Smrg else 498a097bd00Smrg memset (u->ut_host, 0, sizeof (u->ut_host)); 499a6d9b409Smrg#endif 500a6d9b409Smrg u->ut_time = date; 501a6d9b409Smrg} 5021e5fa1c5Smrg#endif /* USE_UTMP */ 503a6d9b409Smrg 504a6d9b409Smrg#ifdef USE_UTMPX 505a6d9b409Smrgstatic int 506a6d9b409SmrgUtmpxIdOpen( char *utmpId ) 507a6d9b409Smrg{ 508a6d9b409Smrg struct utmpx *u; /* pointer to entry in utmp file */ 509a6d9b409Smrg int status = 1; /* return code */ 5101e5fa1c5Smrg 5111e5fa1c5Smrg setutxent(); 512a097bd00Smrg 513a6d9b409Smrg while ( (u = getutxent()) != NULL ) { 514a097bd00Smrg 515a6d9b409Smrg if ( (strncmp(u->ut_id, utmpId, 4) == 0 ) && 516a6d9b409Smrg u->ut_type != DEAD_PROCESS ) { 517a097bd00Smrg 518a6d9b409Smrg status = 0; 519a6d9b409Smrg break; 520a6d9b409Smrg } 521a6d9b409Smrg } 522a097bd00Smrg 5231e5fa1c5Smrg endutxent(); 524a6d9b409Smrg return (status); 525a6d9b409Smrg} 526a6d9b409Smrg 527a6d9b409Smrgstatic void 528a6d9b409Smrgset_utmpx (struct utmpx *u, const char *line, const char *user, 529a097bd00Smrg const char *host, time_t date, int addp) 530a6d9b409Smrg{ 531a6d9b409Smrg static const char letters[] = 532a6d9b409Smrg "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 533a6d9b409Smrg 534b91640d3Smrg memset (u, 0, sizeof (*u)); 535a097bd00Smrg if (line) 536a6d9b409Smrg { 537a097bd00Smrg if(strcmp(line, ":0") == 0) 538a097bd00Smrg (void) strcpy(u->ut_line, "console"); 539a097bd00Smrg else 5408b8e729cSmrg safe_strncpy (u->ut_line, line, sizeof (u->ut_line)); 541a6d9b409Smrg 5428b8e729cSmrg safe_strncpy(u->ut_host, line, sizeof(u->ut_host)); 543a097bd00Smrg#ifdef HAVE_STRUCT_UTMPX_UT_SYSLEN 544a097bd00Smrg u->ut_syslen = strlen(line); 5451e5fa1c5Smrg#endif 546a6d9b409Smrg } 547a097bd00Smrg else 548a097bd00Smrg memset (u->ut_line, 0, sizeof (u->ut_line)); 549a097bd00Smrg if (addp && user) 5508b8e729cSmrg safe_strncpy (u->ut_user, user, sizeof (u->ut_user)); 551a097bd00Smrg else 552a097bd00Smrg memset (u->ut_user, 0, sizeof (u->ut_user)); 553a097bd00Smrg 554a097bd00Smrg if (line) { 555a097bd00Smrg size_t i; 556a097bd00Smrg /* 557a097bd00Smrg * this is a bit crufty, but 558a097bd00Smrg * follows the apparent conventions in 559a097bd00Smrg * the ttys file. ut_id is only 4 bytes 560a097bd00Smrg * long, and the last 4 bytes of the line 561a097bd00Smrg * name are written into it, left justified. 562a097bd00Smrg */ 563a097bd00Smrg i = strlen (line); 564a097bd00Smrg if (i >= sizeof (u->ut_id)) 565a097bd00Smrg i -= sizeof (u->ut_id); 566a097bd00Smrg else 567a097bd00Smrg i = 0; 5688b8e729cSmrg safe_strncpy (u->ut_id, line + i, sizeof (u->ut_id)); 569a6d9b409Smrg 570a6d9b409Smrg /* make sure there is no entry using identical ut_id */ 571a6d9b409Smrg if (!UtmpxIdOpen(u->ut_id) && addp) { 572a097bd00Smrg int limit = sizeof(letters) - 1; 573a097bd00Smrg int t = 0; 574a097bd00Smrg 575a097bd00Smrg u->ut_id[1] = line[i]; 576a097bd00Smrg u->ut_id[2] = line[i+1]; 577a097bd00Smrg u->ut_id[3] = line[i+2]; 578a097bd00Smrg do { 579a097bd00Smrg u->ut_id[0] = letters[t]; 580a097bd00Smrg t++; 581a097bd00Smrg } while (!UtmpxIdOpen(u->ut_id) && (t < limit)); 582a097bd00Smrg } 583a097bd00Smrg if (!addp && strstr(line, ":") != NULL) { 584a097bd00Smrg struct utmpx *tmpu; 585a097bd00Smrg 586a097bd00Smrg while ( (tmpu = getutxent()) != NULL ) { 587a097bd00Smrg if ( (strcmp(tmpu->ut_host, line) == 0 ) && 588a097bd00Smrg tmpu->ut_type != DEAD_PROCESS ) { 589a097bd00Smrg strncpy(u->ut_id, tmpu->ut_id, 590a6d9b409Smrg sizeof(u->ut_id)); 591a097bd00Smrg break; 592a097bd00Smrg } 593a097bd00Smrg } 594a097bd00Smrg endutxent(); 595a097bd00Smrg } 596a097bd00Smrg } else 597a097bd00Smrg memset (u->ut_id, 0, sizeof (u->ut_id)); 598a097bd00Smrg 599a097bd00Smrg if (addp) { 600a097bd00Smrg u->ut_pid = getppid (); 601a097bd00Smrg u->ut_type = USER_PROCESS; 602a097bd00Smrg } else { 603a097bd00Smrg u->ut_pid = 0; 604a097bd00Smrg u->ut_type = DEAD_PROCESS; 605a097bd00Smrg } 606a6d9b409Smrg u->ut_tv.tv_sec = date; 607a6d9b409Smrg u->ut_tv.tv_usec = 0; 608a6d9b409Smrg} 609a6d9b409Smrg#endif /* USE_UTMPX */ 610a6d9b409Smrg 611a097bd00Smrg#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE) 612a6d9b409Smrg/* 613a6d9b409Smrg * compute the slot-number for an X display. This is computed 614a6d9b409Smrg * by counting the lines in /etc/ttys and adding the line-number 615a6d9b409Smrg * that the display appears on in Xservers. This is a poor 61692e95ad1Smrg * design, but is limited by the non-existent interface to utmp. 617a6d9b409Smrg * If host_name is non-NULL, assume it contains the display name, 618a6d9b409Smrg * otherwise use the tty_line argument (i.e., the tty name). 619a6d9b409Smrg */ 620a6d9b409Smrg 621a6d9b409Smrgstatic int 622a6d9b409SmrgXslot (char *ttys_file, char *servers_file, char *tty_line, char *host_name, 623a6d9b409Smrg int addp) 624a6d9b409Smrg{ 625a6d9b409Smrg FILE *ttys, *servers; 626a6d9b409Smrg int c; 627a6d9b409Smrg int slot = 1; 628a6d9b409Smrg int column0 = 1; 629a6d9b409Smrg char servers_line[1024]; 630a6d9b409Smrg char disp_name[512]; 631a6d9b409Smrg int len; 632a6d9b409Smrg char *pos; 633a6d9b409Smrg 634a6d9b409Smrg /* remove screen number from the display name */ 635a6d9b409Smrg memset(disp_name, 0, sizeof(disp_name)); 636a6d9b409Smrg strncpy(disp_name, host_name ? host_name : tty_line, sizeof(disp_name)-1); 637a6d9b409Smrg pos = strrchr(disp_name, ':'); 638a6d9b409Smrg if (pos) { 639a097bd00Smrg pos = strchr(pos, '.'); 640a097bd00Smrg if (pos) 641a097bd00Smrg *pos = '\0'; 642a6d9b409Smrg } 643a6d9b409Smrg sysnerr ((int)(long)(ttys = fopen (ttys_file, "r")), ttys_file); 644a6d9b409Smrg while ((c = getc (ttys)) != EOF) 645a6d9b409Smrg if (c == '\n') { 646a6d9b409Smrg ++slot; 647a6d9b409Smrg column0 = 1; 648a6d9b409Smrg } else 649a6d9b409Smrg column0 = 0; 650a6d9b409Smrg if (!column0) 651a6d9b409Smrg ++slot; 652a6d9b409Smrg (void) fclose (ttys); 653a6d9b409Smrg sysnerr ((int)(long)(servers = fopen (servers_file, "r")), servers_file); 654a6d9b409Smrg 655a6d9b409Smrg len = strlen (disp_name); 656a6d9b409Smrg column0 = 1; 657a6d9b409Smrg while (fgets (servers_line, sizeof (servers_line), servers)) { 658a6d9b409Smrg if (column0 && *servers_line != '#') { 659a6d9b409Smrg if (!strncmp (disp_name, servers_line, len) && 660a6d9b409Smrg (servers_line[len] == ' ' || 661a6d9b409Smrg servers_line[len] == '\t')) 662a6d9b409Smrg return slot; 663a6d9b409Smrg ++slot; 664a6d9b409Smrg } 665a6d9b409Smrg if (servers_line[strlen(servers_line)-1] != '\n') 666a6d9b409Smrg column0 = 0; 667a6d9b409Smrg else 668a6d9b409Smrg column0 = 1; 669a6d9b409Smrg } 670a6d9b409Smrg /* 67192e95ad1Smrg * display not found in Xservers file - allocate utmp entry dynamically 672a6d9b409Smrg */ 673a6d9b409Smrg return findslot (tty_line, host_name, addp, slot); 674a6d9b409Smrg} 675a6d9b409Smrg 676a6d9b409Smrg/* 677a6d9b409Smrg * find a free utmp slot for the X display. This allocates a new entry 678a6d9b409Smrg * past the regular tty entries if necessary, reusing existing entries 679a6d9b409Smrg * (identified by (line,hostname)) if possible. 680a6d9b409Smrg */ 681a6d9b409Smrgstatic int 682a6d9b409Smrgfindslot (char *line_name, char *host_name, int addp, int slot) 683a6d9b409Smrg{ 684a6d9b409Smrg int utmp; 685a6d9b409Smrg struct utmp entry; 686a6d9b409Smrg int found = 0; 687a6d9b409Smrg int freeslot = -1; 688a6d9b409Smrg 689a6d9b409Smrg syserr(utmp = open (utmp_file, O_RDONLY), "open utmp"); 690a6d9b409Smrg 691a6d9b409Smrg /* 692a6d9b409Smrg * first, try to locate a previous entry for this display 693a6d9b409Smrg * also record location of a free slots in case we need a new one 694a6d9b409Smrg */ 69511a95ff3Smrg syserr ((int) lseek (utmp, (off_t) slot * sizeof (struct utmp), 0), "lseek"); 696a6d9b409Smrg 697a6d9b409Smrg if (!host_name) 698a6d9b409Smrg host_name = ""; 699a6d9b409Smrg 700a6d9b409Smrg while (read (utmp, (char *) &entry, sizeof (entry)) == sizeof (entry)) { 701a6d9b409Smrg if (strncmp(entry.ut_line, line_name, 702a097bd00Smrg sizeof(entry.ut_line)) == 0 703a097bd00Smrg#ifdef HAVE_STRUCT_UTMP_UT_HOST 704a097bd00Smrg && 705a6d9b409Smrg strncmp(entry.ut_host, host_name, 706a6d9b409Smrg sizeof(entry.ut_host)) == 0 707a6d9b409Smrg#endif 708a097bd00Smrg ) { 709a6d9b409Smrg found = 1; 710a6d9b409Smrg break; 711a6d9b409Smrg } 712a6d9b409Smrg if (freeslot < 0 && *entry.ut_name == '\0') 713a6d9b409Smrg freeslot = slot; 714a6d9b409Smrg ++slot; 715a6d9b409Smrg } 716a6d9b409Smrg 717a6d9b409Smrg close (utmp); 718a6d9b409Smrg 719a6d9b409Smrg if (found) 720a6d9b409Smrg return slot; 721a6d9b409Smrg else if (!addp) 722a6d9b409Smrg return 0; /* trying to delete a non-existing entry */ 723a6d9b409Smrg else if (freeslot < 0) 724a6d9b409Smrg return slot; /* first slot past current entries */ 725a6d9b409Smrg else 726a6d9b409Smrg return freeslot; 727a6d9b409Smrg} 728a6d9b409Smrg#endif 729