2
* $Xorg: sessreg.c,v 1.5 2000/08/17 19:54:15 cpqbld Exp $
5
* Copyright 1990, 1998 The Open Group
7
* Permission to use, copy, modify, distribute, and sell this software and its
8
* documentation for any purpose is hereby granted without fee, provided that
9
* the above copyright notice appear in all copies and that both that
10
* copyright notice and this permission notice appear in supporting
13
* The above copyright notice and this permission notice shall be included
14
* in all copies or substantial portions of the Software.
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
* IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
* OTHER DEALINGS IN THE SOFTWARE.
24
* Except as contained in this notice, the name of The Open Group shall
25
* not be used in advertising or otherwise to promote the sale, use or
26
* other dealings in this Software without prior written authorization
27
* from The Open Group.
31
/* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
33
* Permission is hereby granted, free of charge, to any person obtaining a
34
* copy of this software and associated documentation files (the
35
* "Software"), to deal in the Software without restriction, including
36
* without limitation the rights to use, copy, modify, merge, publish,
37
* distribute, and/or sell copies of the Software, and to permit persons
38
* to whom the Software is furnished to do so, provided that the above
39
* copyright notice(s) and this permission notice appear in all copies of
40
* the Software and that both the above copyright notice(s) and this
41
* permission notice appear in supporting documentation.
43
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
44
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
45
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
46
* OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
47
* HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
48
* INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
49
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
50
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
51
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
53
* Except as contained in this notice, the name of a copyright holder
54
* shall not be used in advertising or otherwise to promote the sale, use
55
* or other dealings in this Software without prior written authorization
56
* of the copyright holder.
60
* Author: Keith Packard, MIT X Consortium
61
* Lastlog support and dynamic utmp entry allocation
62
* by Andreas Stolcke <stolcke@icsi.berkeley.edu>
65
/* $XFree86: xc/programs/xdm/sessreg.c,v 3.18 2001/12/14 20:01:24 dawes Exp $ */
70
* simple wtmp/utmp frobber
72
* usage: sessreg [ -w <wtmp-file> ] [ -u <utmp-file> ]
74
* [ -h <host-name> ] / BSD only
75
* [ -s <slot-number> ] [ -x Xservers-file ] / BSD only
76
* [ -t <ttys-file> ] / BSD only
77
* [ -a ] [ -d ] user-name
79
* one of -a or -d must be specified
87
# include <X11/Xfuncs.h>
92
#ifndef HAVE_CONFIG_H /* Imake fallback - hardcode platforms with utmpx */
93
# if (defined(sun) && defined (__SVR4))
95
# define HAVE_UTMPX_UT_SYSLEN 1
100
# if HAVE_UTMPX_UT_SYSLEN
107
# ifndef HAVE_LASTLOG_H
111
# if defined(SYSV) || (defined(SVR4) && !defined(sun)) || defined(Lynx) || defined(__QNX__) || defined(__DARWIN__) || defined(_SEQUENT_)
116
#if defined(CSRG_BASED) || defined(HAVE_SYS_PARAM_H)
117
#include <sys/param.h>
123
# include <lastlog.h>
126
# include <lastlog.h>
131
#if defined(__SVR4) || defined(SVR4) || defined(linux) || defined(__GLIBC__)
136
#if !defined(__FreeBSD__) && !defined(__OpenBSD__)
137
/* *BSD doesn't like a ':0' type entry in utmp */
144
# define WTMP_FILE _PATH_WTMP
146
# define WTMP_FILE "/usr/adm/wtmp"
151
# define UTMP_FILE _PATH_UTMP
153
# define UTMP_FILE "/etc/utmp"
158
# ifdef _PATH_LASTLOG
159
# define LLOG_FILE _PATH_LASTLOG
161
# define LLOG_FILE "/usr/adm/lastlog"
167
# define TTYS_FILE "/etc/ttys"
172
#define Time_t time_t
174
extern long lseek ();
175
extern char *ttyname ();
178
static void set_utmp (struct utmp *u, char *line, char *user, char *host, Time_t date, int addp);
181
static void set_utmpx (struct utmpx *u, const char *line, const char *user,
182
const char *host, Time_t date, int addp);
185
int wflag, uflag, lflag;
186
char *wtmp_file, *utmp_file, *line;
188
static char *wtmpx_file = NULL, *utmpx_file = NULL;
190
int utmp_none, wtmp_none;
192
* BSD specific variables. To make life much easier for Xstartup/Xreset
193
* maintainers, these arguments are accepted but ignored for sysV
195
int hflag, sflag, xflag, tflag;
196
char *host_name = NULL;
198
char *xservers_file, *ttys_file;
203
int llog_none, Lflag;
209
static int findslot (char *line_name, char *host_name, int addp, int slot);
210
static int Xslot (char *ttys_file, char *servers_file, char *tty_line,
211
char *host_name, int addp);
218
fprintf (stderr, "%s: usage %s {-a -d} [-w wtmp-file] [-u utmp-file]", program_name, program_name);
220
fprintf (stderr, " [-L lastlog-file]");
222
fprintf (stderr, "\n");
223
fprintf (stderr, " [-t ttys-file] [-l line-name] [-h host-name]\n");
224
fprintf (stderr, " [-s slot-number] [-x servers-file] user-name\n");
231
getstring (char ***avp, int *flagp)
246
syserr (int x, const char *s)
257
sysnerr (int x, const char *s)
267
main (int argc, char **argv)
275
struct utmp utmp_entry;
278
struct utmpx utmpx_entry;
281
program_name = argv[0];
282
while (*++argv && **argv == '-') {
285
wtmp_file = getstring (&argv, &wflag);
286
if (!strcmp (wtmp_file, "none"))
290
utmp_file = getstring (&argv, &uflag);
291
if (!strcmp (utmp_file, "none"))
296
llog_file = getstring (&argv, &Lflag);
297
if (!strcmp (llog_file, "none"))
302
ttys_file = getstring (&argv, &tflag);
305
line = getstring (&argv, &lflag);
308
host_name = getstring (&argv, &hflag);
311
slot_number = atoi (getstring (&argv, &sflag));
314
xservers_file = getstring (&argv, &xflag);
326
usage (!(user_name = *argv++));
329
* complain if neither aflag nor dflag are set,
330
* or if both are set.
332
usage (!(aflag ^ dflag));
333
usage (xflag && !lflag);
334
/* set up default file names */
336
wtmp_file = WTMP_FILE;
338
wtmpx_file = WTMPX_FILE;
343
utmp_file = UTMP_FILE;
345
utmpx_file = UTMPX_FILE;
353
llog_file = LLOG_FILE;
355
#if !defined(SYSV) && !defined(linux) && !defined(__QNX__)
357
ttys_file = TTYS_FILE;
358
if (!sflag && !utmp_none) {
360
sysnerr (slot_number = Xslot (ttys_file, xservers_file, line, host_name, aflag), "Xslot");
362
sysnerr (slot_number = ttyslot (), "ttyslot");
366
sysnerr ((line_tmp = ttyname (0)) != NULL, "ttyname");
367
line = strrchr(line_tmp, '/');
373
time (¤t_time);
374
set_utmp (&utmp_entry, line, user_name, host_name, current_time, aflag);
377
/* need to set utmpxname() before calling set_utmpx() for
378
UtmpxIdOpen to work */
379
if (utmpx_file != NULL) {
380
utmpxname (utmpx_file);
382
set_utmpx (&utmpx_entry, line, user_name,
383
host_name, current_time, aflag);
388
if (utmpx_file != NULL) {
390
(void) getutxid (&utmpx_entry);
391
pututxline (&utmpx_entry);
396
utmpname (utmp_file);
398
(void) getutid (&utmp_entry);
399
pututline (&utmp_entry);
402
utmp = open (utmp_file, O_RDWR);
404
syserr ((int) lseek (utmp, (long) slot_number * sizeof (struct utmp), 0), "lseek");
405
sysnerr (write (utmp, (char *) &utmp_entry, sizeof (utmp_entry))
406
== sizeof (utmp_entry), "write utmp entry");
413
if (wtmpx_file != NULL) {
414
updwtmpx(wtmpx_file, &utmpx_entry);
417
wtmp = open (wtmp_file, O_WRONLY|O_APPEND);
419
sysnerr (write (wtmp, (char *) &utmp_entry, sizeof (utmp_entry))
420
== sizeof (utmp_entry), "write wtmp entry");
426
if (aflag && !llog_none) {
428
struct passwd *pwd = getpwnam(user_name);
430
sysnerr( pwd != NULL, "get user id");
431
llog = open (llog_file, O_RDWR);
436
sysnerr (lseek(llog, (long) pwd->pw_uid*sizeof(ll), 0)
437
!= -1, "seeking lastlog entry");
438
bzero((char *)&ll, sizeof(ll));
439
ll.ll_time = current_time;
441
(void) strncpy (ll.ll_line, line, sizeof (ll.ll_line));
443
(void) strncpy (ll.ll_host, host_name, sizeof (ll.ll_host));
445
sysnerr (write (llog, (char *) &ll, sizeof (ll))
446
== sizeof (ll), "write lastlog entry");
455
* fill in the appropriate records of the utmp entry
459
set_utmp (struct utmp *u, char *line, char *user, char *host, Time_t date, int addp)
461
bzero (u, sizeof (*u));
463
(void) strncpy (u->ut_line, line, sizeof (u->ut_line));
465
bzero (u->ut_line, sizeof (u->ut_line));
467
(void) strncpy (u->ut_name, user, sizeof (u->ut_name));
469
bzero (u->ut_name, sizeof (u->ut_name));
474
* this is a bit crufty, but
475
* follows the apparent conventions in
476
* the ttys file. ut_id is only 4 bytes
477
* long, and the last 4 bytes of the line
478
* name are written into it, left justified.
481
if (i >= sizeof (u->ut_id))
482
i -= sizeof (u->ut_id);
485
(void) strncpy (u->ut_id, line + i, sizeof (u->ut_id));
487
bzero (u->ut_id, sizeof (u->ut_id));
489
u->ut_pid = getppid ();
490
u->ut_type = USER_PROCESS;
493
u->ut_type = DEAD_PROCESS;
496
#if (!defined(SYSV) && !defined(__QNX__)) || defined(linux)
498
(void) strncpy (u->ut_host, host, sizeof (u->ut_host));
500
bzero (u->ut_host, sizeof (u->ut_host));
507
UtmpxIdOpen( char *utmpId )
509
struct utmpx *u; /* pointer to entry in utmp file */
510
int status = 1; /* return code */
512
while ( (u = getutxent()) != NULL ) {
514
if ( (strncmp(u->ut_id, utmpId, 4) == 0 ) &&
515
u->ut_type != DEAD_PROCESS ) {
527
set_utmpx (struct utmpx *u, const char *line, const char *user,
528
const char *host, Time_t date, int addp)
530
static const char letters[] =
531
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
535
if(strcmp(line, ":0") == 0)
536
(void) strcpy(u->ut_line, "console");
538
(void) strncpy (u->ut_line, line, sizeof (u->ut_line));
540
strncpy(u->ut_host, line, sizeof(u->ut_host));
541
u->ut_syslen = strlen(line);
544
bzero (u->ut_line, sizeof (u->ut_line));
546
(void) strncpy (u->ut_name, user, sizeof (u->ut_name));
548
bzero (u->ut_name, sizeof (u->ut_name));
553
* this is a bit crufty, but
554
* follows the apparent conventions in
555
* the ttys file. ut_id is only 4 bytes
556
* long, and the last 4 bytes of the line
557
* name are written into it, left justified.
560
if (i >= sizeof (u->ut_id))
561
i -= sizeof (u->ut_id);
564
(void) strncpy (u->ut_id, line + i, sizeof (u->ut_id));
566
/* make sure there is no entry using identical ut_id */
567
if (!UtmpxIdOpen(u->ut_id) && addp) {
568
int limit = sizeof(letters) - 1;
571
u->ut_id[1] = line[i];
572
u->ut_id[2] = line[i+1];
573
u->ut_id[3] = line[i+2];
575
u->ut_id[0] = letters[t];
577
} while (!UtmpxIdOpen(u->ut_id) && (t < limit));
579
if (!addp && strstr(line, ":") != NULL) {
582
while ( (tmpu = getutxent()) != NULL ) {
583
if ( (strcmp(tmpu->ut_host, line) == 0 ) &&
584
tmpu->ut_type != DEAD_PROCESS ) {
585
strncpy(u->ut_id, tmpu->ut_id,
593
bzero (u->ut_id, sizeof (u->ut_id));
596
u->ut_pid = getppid ();
597
u->ut_type = USER_PROCESS;
600
u->ut_type = DEAD_PROCESS;
602
u->ut_tv.tv_sec = date;
603
u->ut_tv.tv_usec = 0;
605
#endif /* USE_UTMPX */
609
* compute the slot-number for an X display. This is computed
610
* by counting the lines in /etc/ttys and adding the line-number
611
* that the display appears on in Xservers. This is a poor
612
* design, but is limited by the non-existant interface to utmp.
613
* If host_name is non-NULL, assume it contains the display name,
614
* otherwise use the tty_line argument (i.e., the tty name).
618
Xslot (char *ttys_file, char *servers_file, char *tty_line, char *host_name,
621
FILE *ttys, *servers;
625
char servers_line[1024];
630
/* remove screen number from the display name */
631
memset(disp_name, 0, sizeof(disp_name));
632
strncpy(disp_name, host_name ? host_name : tty_line, sizeof(disp_name)-1);
633
pos = strrchr(disp_name, ':');
635
pos = strchr(pos, '.');
639
sysnerr ((int)(long)(ttys = fopen (ttys_file, "r")), ttys_file);
640
while ((c = getc (ttys)) != EOF)
648
(void) fclose (ttys);
649
sysnerr ((int)(long)(servers = fopen (servers_file, "r")), servers_file);
651
len = strlen (disp_name);
653
while (fgets (servers_line, sizeof (servers_line), servers)) {
654
if (column0 && *servers_line != '#') {
655
if (!strncmp (disp_name, servers_line, len) &&
656
(servers_line[len] == ' ' ||
657
servers_line[len] == '\t'))
661
if (servers_line[strlen(servers_line)-1] != '\n')
667
* display not found in Xservers file - allocate utmp entry dinamically
669
return findslot (tty_line, host_name, addp, slot);
673
* find a free utmp slot for the X display. This allocates a new entry
674
* past the regular tty entries if necessary, reusing existing entries
675
* (identified by (line,hostname)) if possible.
678
findslot (char *line_name, char *host_name, int addp, int slot)
685
syserr(utmp = open (utmp_file, O_RDONLY), "open utmp");
688
* first, try to locate a previous entry for this display
689
* also record location of a free slots in case we need a new one
691
syserr ((int) lseek (utmp, (long) slot * sizeof (struct utmp), 0), "lseek");
696
while (read (utmp, (char *) &entry, sizeof (entry)) == sizeof (entry)) {
697
if (strncmp(entry.ut_line, line_name,
698
sizeof(entry.ut_line)) == 0
701
strncmp(entry.ut_host, host_name,
702
sizeof(entry.ut_host)) == 0
708
if (freeslot < 0 && *entry.ut_name == '\0')
718
return 0; /* trying to delete a non-existing entry */
719
else if (freeslot < 0)
720
return slot; /* first slot past current entries */