Tizen 2.0 Release
[framework/uifw/xorg/util/x11-xserver-utils.git] / sessreg / sessreg.c
1 /*
2  * Copyright 1990, 1998  The Open Group
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.
9  *
10  * The above copyright notice and this permission notice shall be included
11  * in all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  * IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
17  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19  * OTHER DEALINGS IN THE SOFTWARE.
20  *
21  * Except as contained in this notice, the name of The Open Group shall
22  * not be used in advertising or otherwise to promote the sale, use or
23  * other dealings in this Software without prior written authorization
24  * from The Open Group.
25  *
26  */
27
28 /*
29  * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
30  *
31  * Permission is hereby granted, free of charge, to any person obtaining a
32  * copy of this software and associated documentation files (the "Software"),
33  * to deal in the Software without restriction, including without limitation
34  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
35  * and/or sell copies of the Software, and to permit persons to whom the
36  * Software is furnished to do so, subject to the following conditions:
37  *
38  * The above copyright notice and this permission notice (including the next
39  * paragraph) shall be included in all copies or substantial portions of the
40  * Software.
41  *
42  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
45  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
47  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
48  * DEALINGS IN THE SOFTWARE.
49  */
50
51 /*
52  * Author:  Keith Packard, MIT X Consortium
53  * Lastlog support and dynamic utmp entry allocation
54  *   by Andreas Stolcke <stolcke@icsi.berkeley.edu>
55  */
56
57 /*
58  * sessreg
59  *
60  * simple wtmp/utmp frobber
61  *
62  * usage: sessreg [ -w <wtmp-file> ] [ -u <utmp-file> ]
63  *                [ -l <line> ]
64  *                [ -L <lastlog-file> ]               / #ifdef USE_LASTLOG
65  *                [ -h <host-name> ]                            / BSD only
66  *                [ -s <slot-number> ] [ -x Xservers-file ]     / BSD only
67  *                [ -t <ttys-file> ]                            / BSD only
68  *                [ -a ] [ -d ] user-name
69  *
70  * one of -a or -d must be specified
71  */
72
73 #include "sessreg.h"
74
75 #include <X11/Xos.h>
76 #include <X11/Xfuncs.h>
77 #include <stdio.h>
78 #include <stdlib.h>
79 #include <time.h>
80
81 #ifdef USE_UTMP
82 static void set_utmp (struct utmp *u, char *line, char *user, char *host,
83                       time_t date, int addp);
84 #endif
85
86 #ifdef USE_UTMPX
87 static void set_utmpx (struct utmpx *u, const char *line, const char *user,
88                        const char *host, time_t date, int addp);
89 #endif
90
91 static int wflag, uflag, lflag;
92 static const char *wtmp_file, *utmp_file;
93 static char *line;
94 #ifdef USE_UTMPX
95 #ifdef HAVE_UPDWTMPX
96 static const char *wtmpx_file = NULL;
97 #endif
98 #ifdef HAVE_UTMPXNAME
99 static const char *utmpx_file = NULL;
100 #endif
101 #endif
102 static int utmp_none, wtmp_none;
103 /*
104  * BSD specific variables.  To make life much easier for Xstartup/Xreset
105  * maintainers, these arguments are accepted but ignored for sysV
106  */
107 static int hflag, xflag, tflag;
108 static char *host_name = NULL;
109 #if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE)
110 static int sflag;
111 static int slot_number;
112 #endif
113 static char *xservers_file, *ttys_file;
114 static char *user_name;
115 static int aflag, dflag;
116 #ifdef USE_LASTLOG
117 static const char *llog_file;
118 static int llog_none, Lflag;
119 #endif
120
121 static char *program_name;
122
123 #if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE)
124 static int findslot (char *line_name, char *host_name, int addp, int slot);
125 static int Xslot (char *ttys_file, char *servers_file, char *tty_line,
126                   char *host_name, int addp);
127 #endif
128
129 static int
130 usage (int x)
131 {
132         if (x) {
133                 fprintf (stderr, "%s: usage %s {-a -d} [-w wtmp-file] [-u utmp-file]", program_name, program_name);
134 #ifdef USE_LASTLOG
135                 fprintf (stderr, " [-L lastlog-file]");
136 #endif
137                 fprintf (stderr, "\n");
138                 fprintf (stderr, "             [-t ttys-file] [-l line-name] [-h host-name]\n");
139                 fprintf (stderr, "             [-s slot-number] [-x servers-file] user-name\n");
140                 exit (1);
141         }
142         return x;
143 }
144
145 static char *
146 getstring (char ***avp, int *flagp)
147 {
148         char    **a = *avp;
149
150         usage ((*flagp)++);
151         if (*++*a)
152                 return *a;
153         ++a;
154         usage (!*a);
155         *avp = a;
156         return *a;
157 }
158
159 #if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE)
160 static int
161 syserr (int x, const char *s)
162 {
163         if (x == -1) {
164                 perror (s);
165                 exit (1);
166         }
167         return x;
168 }
169 #endif
170
171 static int
172 sysnerr (int x, const char *s)
173 {
174         if (x == 0) {
175                 perror (s);
176                 exit (1);
177         }
178         return x;
179 }
180
181 int
182 main (int argc, char **argv)
183 {
184 #if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE)
185         int             utmp;
186 #endif
187 #ifndef USE_UTMPX
188         int             wtmp;
189 #endif
190         time_t          current_time;
191 #ifdef USE_UTMP
192         struct utmp     utmp_entry;
193 #endif
194 #ifdef USE_UTMPX
195         struct utmpx    utmpx_entry;
196 #endif
197
198         program_name = argv[0];
199         while (*++argv && **argv == '-') {
200                 switch (*++*argv) {
201                 case 'w':
202                         wtmp_file = getstring (&argv, &wflag);
203                         if (!strcmp (wtmp_file, "none"))
204                                 wtmp_none = 1;
205                         break;
206                 case 'u':
207                         utmp_file = getstring (&argv, &uflag);
208                         if (!strcmp (utmp_file, "none"))
209                                 utmp_none = 1;
210                         break;
211 #ifdef USE_LASTLOG
212                 case 'L':
213                         llog_file = getstring (&argv, &Lflag);
214                         if (!strcmp (llog_file, "none"))
215                                 llog_none = 1;
216                         break;
217 #endif
218                 case 't':
219                         ttys_file = getstring (&argv, &tflag);
220                         break;
221                 case 'l':
222                         line = getstring (&argv, &lflag);
223                         break;
224                 case 'h':
225                         host_name = getstring (&argv, &hflag);
226                         break;
227                 case 's':
228 #if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE)
229                         slot_number = atoi (getstring (&argv, &sflag));
230 #endif
231                         break;
232                 case 'x':
233                         xservers_file = getstring (&argv, &xflag);
234                         break;
235                 case 'a':
236                         aflag++;
237                         break;
238                 case 'd':
239                         dflag++;
240                         break;
241                 default:
242                         usage (1);
243                 }
244         }
245         usage (!(user_name = *argv++));
246         usage (*argv != NULL);
247         /*
248          * complain if neither aflag nor dflag are set,
249          * or if both are set.
250          */
251         usage (!(aflag ^ dflag));
252         usage (xflag && !lflag);
253         /* set up default file names */
254         if (!wflag) {
255                 wtmp_file = WTMP_FILE;
256 #if defined(USE_UTMPX) && defined(HAVE_UPDWTMPX)
257                 wtmpx_file = WTMPX_FILE;
258 #endif
259         }
260 #ifndef NO_UTMP
261         if (!uflag) {
262                 utmp_file = UTMP_FILE;
263 #if defined(USE_UTMPX) && defined(HAVE_UTMPXNAME)
264                 utmpx_file = UTMPX_FILE;
265 #endif
266         }
267 #else
268         utmp_none = 1;
269 #endif
270 #ifdef USE_LASTLOG
271         if (!Lflag)
272                 llog_file = LLOG_FILE;
273 #endif
274 #if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE)
275         if (!tflag)
276                 ttys_file = TTYS_FILE;
277         if (!sflag && !utmp_none) {
278                 if (xflag)
279                         sysnerr (slot_number = Xslot (ttys_file, xservers_file, line, host_name, aflag), "Xslot");
280                 else
281                         sysnerr (slot_number = ttyslot (), "ttyslot");
282         }
283 #endif
284         if (!lflag) {
285                 sysnerr ((line = ttyname (0)) != NULL, "ttyname");
286                 if (strncmp(line, "/dev/", 5) == 0)
287                         line += 5;
288         }
289         time (&current_time);
290 #ifdef USE_UTMP
291         set_utmp (&utmp_entry, line, user_name, host_name, current_time, aflag);
292 #endif
293
294 #ifdef USE_UTMPX
295         /* need to set utmpxname() before calling set_utmpx() for
296            UtmpxIdOpen to work */
297 # ifdef HAVE_UTMPXNAME
298         if (utmpx_file != NULL) {
299                 utmpxname (utmpx_file);
300         }
301 # endif
302         set_utmpx (&utmpx_entry, line, user_name,
303                    host_name, current_time, aflag);
304 #endif
305
306         if (!utmp_none) {
307 #ifdef USE_UTMPX
308 # ifdef HAVE_UTMPXNAME
309                 if (utmpx_file != NULL)
310 # endif
311                 {
312                         setutxent ();
313                         (void) getutxid (&utmpx_entry);
314                         pututxline (&utmpx_entry);
315                         endutxent ();
316                 }
317 #endif
318 #ifdef USE_UTMP
319 # ifdef HAVE_PUTUTLINE
320                 utmpname (utmp_file);
321                 setutent ();
322                 (void) getutid (&utmp_entry);
323                 pututline (&utmp_entry);
324                 endutent ();
325 # else
326                 utmp = open (utmp_file, O_RDWR);
327                 if (utmp != -1) {
328                         syserr ((int) lseek (utmp, (long) slot_number * sizeof (struct utmp), 0), "lseek");
329                         sysnerr (write (utmp, (char *) &utmp_entry, sizeof (utmp_entry))
330                                         == sizeof (utmp_entry), "write utmp entry");
331                         close (utmp);
332                 }
333 # endif
334 #endif /* USE_UTMP */
335         }
336         if (!wtmp_none) {
337 #ifdef USE_UTMPX
338 # ifdef HAVE_UPDWTMPX
339                 if (wtmpx_file != NULL) {
340                         updwtmpx(wtmpx_file, &utmpx_entry);
341                 }
342 # endif
343 #else
344                 wtmp = open (wtmp_file, O_WRONLY|O_APPEND);
345                 if (wtmp != -1) {
346                         sysnerr (write (wtmp, (char *) &utmp_entry, sizeof (utmp_entry))
347                                         == sizeof (utmp_entry), "write wtmp entry");
348                         close (wtmp);
349                 }
350 #endif
351         }
352 #ifdef USE_LASTLOG
353         if (aflag && !llog_none) {
354                 int llog;
355                 struct passwd *pwd = getpwnam(user_name);
356
357                 sysnerr( pwd != NULL, "get user id");
358                 llog = open (llog_file, O_RDWR);
359
360                 if (llog != -1) {
361                         struct lastlog ll;
362
363                         sysnerr (lseek(llog, (long) pwd->pw_uid*sizeof(ll), 0)
364                                         != -1, "seeking lastlog entry");
365                         memset(&ll, 0, sizeof(ll));
366                         ll.ll_time = current_time;
367                         if (line)
368                          (void) strncpy (ll.ll_line, line, sizeof (ll.ll_line));
369                         if (host_name)
370                          (void) strncpy (ll.ll_host, host_name, sizeof (ll.ll_host));
371
372                         sysnerr (write (llog, (char *) &ll, sizeof (ll))
373                                         == sizeof (ll), "write lastlog entry");
374                         close (llog);
375                 }
376         }
377 #endif
378         return 0;
379 }
380
381 /*
382  * fill in the appropriate records of the utmp entry
383  */
384
385 #ifdef USE_UTMP
386 static void
387 set_utmp (struct utmp *u, char *line, char *user, char *host, time_t date, int addp)
388 {
389         memset (u, 0, sizeof (*u));
390         if (line)
391                 (void) strncpy (u->ut_line, line, sizeof (u->ut_line));
392         else
393                 memset (u->ut_line, 0, sizeof (u->ut_line));
394         if (addp && user)
395                 (void) strncpy (u->ut_name, user, sizeof (u->ut_name));
396         else
397                 memset (u->ut_name, 0, sizeof (u->ut_name));
398 #ifdef HAVE_STRUCT_UTMP_UT_ID
399         if (line) {
400                 int     i;
401                 /*
402                  * this is a bit crufty, but
403                  * follows the apparent conventions in
404                  * the ttys file.  ut_id is only 4 bytes
405                  * long, and the last 4 bytes of the line
406                  * name are written into it, left justified.
407                  */
408                 i = strlen (line);
409                 if (i >= sizeof (u->ut_id))
410                         i -= sizeof (u->ut_id);
411                 else
412                         i = 0;
413                 (void) strncpy (u->ut_id, line + i, sizeof (u->ut_id));
414         } else
415                 memset (u->ut_id, 0, sizeof (u->ut_id));
416 #endif
417 #ifdef HAVE_STRUCT_UTMP_UT_PID
418         if (addp)
419                 u->ut_pid = getppid ();
420         else
421                 u->ut_pid = 0;
422 #endif
423 #ifdef HAVE_STRUCT_UTMP_UT_TYPE
424         if (addp)
425                 u->ut_type = USER_PROCESS;
426         else
427                 u->ut_type = DEAD_PROCESS;
428 #endif
429 #ifdef HAVE_STRUCT_UTMP_UT_HOST
430         if (addp && host)
431                 (void) strncpy (u->ut_host, host, sizeof (u->ut_host));
432         else
433                 memset (u->ut_host, 0, sizeof (u->ut_host));
434 #endif
435         u->ut_time = date;
436 }
437 #endif /* USE_UTMP */
438
439 #ifdef USE_UTMPX
440 static int
441 UtmpxIdOpen( char *utmpId )
442 {
443         struct utmpx *u;        /* pointer to entry in utmp file           */
444         int    status = 1;      /* return code                             */
445
446         setutxent();
447
448         while ( (u = getutxent()) != NULL ) {
449
450                 if ( (strncmp(u->ut_id, utmpId, 4) == 0 ) &&
451                      u->ut_type != DEAD_PROCESS ) {
452
453                         status = 0;
454                         break;
455                 }
456         }
457
458         endutxent();
459         return (status);
460 }
461
462 static void
463 set_utmpx (struct utmpx *u, const char *line, const char *user,
464            const char *host, time_t date, int addp)
465 {
466         static const char letters[] =
467                "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
468
469         if (line)
470         {
471                 if(strcmp(line, ":0") == 0)
472                         (void) strcpy(u->ut_line, "console");
473                 else
474                         (void) strncpy (u->ut_line, line, sizeof (u->ut_line));
475
476                 strncpy(u->ut_host, line, sizeof(u->ut_host));
477 #ifdef HAVE_STRUCT_UTMPX_UT_SYSLEN
478                 u->ut_syslen = strlen(line);
479 #endif
480         }
481         else
482                 memset (u->ut_line, 0, sizeof (u->ut_line));
483         if (addp && user)
484                 (void) strncpy (u->ut_user, user, sizeof (u->ut_user));
485         else
486                 memset (u->ut_user, 0, sizeof (u->ut_user));
487
488         if (line) {
489                 int     i;
490                 /*
491                  * this is a bit crufty, but
492                  * follows the apparent conventions in
493                  * the ttys file.  ut_id is only 4 bytes
494                  * long, and the last 4 bytes of the line
495                  * name are written into it, left justified.
496                  */
497                 i = strlen (line);
498                 if (i >= sizeof (u->ut_id))
499                         i -= sizeof (u->ut_id);
500                 else
501                         i = 0;
502                 (void) strncpy (u->ut_id, line + i, sizeof (u->ut_id));
503
504                 /* make sure there is no entry using identical ut_id */
505                 if (!UtmpxIdOpen(u->ut_id) && addp) {
506                         int limit = sizeof(letters) - 1;
507                         int t = 0;
508
509                         u->ut_id[1] = line[i];
510                         u->ut_id[2] = line[i+1];
511                         u->ut_id[3] = line[i+2];
512                         do {
513                                 u->ut_id[0] = letters[t];
514                                 t++;
515                         } while (!UtmpxIdOpen(u->ut_id) && (t < limit));
516                 }
517                 if (!addp && strstr(line, ":") != NULL) {
518                         struct utmpx *tmpu;
519
520                         while ( (tmpu = getutxent()) != NULL ) {
521                                 if ( (strcmp(tmpu->ut_host, line) == 0 ) &&
522                                         tmpu->ut_type != DEAD_PROCESS ) {
523                                         strncpy(u->ut_id, tmpu->ut_id,
524                                                 sizeof(u->ut_id));
525                                         break;
526                                 }
527                         }
528                         endutxent();
529                 }
530         } else
531                 memset (u->ut_id, 0, sizeof (u->ut_id));
532
533         if (addp) {
534                 u->ut_pid = getppid ();
535                 u->ut_type = USER_PROCESS;
536         } else {
537                 u->ut_pid = 0;
538                 u->ut_type = DEAD_PROCESS;
539         }
540         u->ut_tv.tv_sec = date;
541         u->ut_tv.tv_usec = 0;
542 }
543 #endif /* USE_UTMPX */
544
545 #if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE)
546 /*
547  * compute the slot-number for an X display.  This is computed
548  * by counting the lines in /etc/ttys and adding the line-number
549  * that the display appears on in Xservers.  This is a poor
550  * design, but is limited by the non-existant interface to utmp.
551  * If host_name is non-NULL, assume it contains the display name,
552  * otherwise use the tty_line argument (i.e., the tty name).
553  */
554
555 static int
556 Xslot (char *ttys_file, char *servers_file, char *tty_line, char *host_name,
557        int addp)
558 {
559         FILE    *ttys, *servers;
560         int     c;
561         int     slot = 1;
562         int     column0 = 1;
563         char    servers_line[1024];
564         char    disp_name[512];
565         int     len;
566         char    *pos;
567
568         /* remove screen number from the display name */
569         memset(disp_name, 0, sizeof(disp_name));
570         strncpy(disp_name, host_name ? host_name : tty_line, sizeof(disp_name)-1);
571         pos = strrchr(disp_name, ':');
572         if (pos) {
573                 pos = strchr(pos, '.');
574                 if (pos)
575                         *pos = '\0';
576         }
577         sysnerr ((int)(long)(ttys = fopen (ttys_file, "r")), ttys_file);
578         while ((c = getc (ttys)) != EOF)
579                 if (c == '\n') {
580                         ++slot;
581                         column0 = 1;
582                 } else
583                         column0 = 0;
584         if (!column0)
585                 ++slot;
586         (void) fclose (ttys);
587         sysnerr ((int)(long)(servers = fopen (servers_file, "r")), servers_file);
588
589         len = strlen (disp_name);
590         column0 = 1;
591         while (fgets (servers_line, sizeof (servers_line), servers)) {
592                 if (column0 && *servers_line != '#') {
593                         if (!strncmp (disp_name, servers_line, len) &&
594                             (servers_line[len] == ' ' ||
595                              servers_line[len] == '\t'))
596                                 return slot;
597                         ++slot;
598                 }
599                 if (servers_line[strlen(servers_line)-1] != '\n')
600                         column0 = 0;
601                 else
602                         column0 = 1;
603         }
604         /*
605          * display not found in Xservers file - allocate utmp entry dinamically
606          */
607         return findslot (tty_line, host_name, addp, slot);
608 }
609
610 /*
611  * find a free utmp slot for the X display.  This allocates a new entry
612  * past the regular tty entries if necessary, reusing existing entries
613  * (identified by (line,hostname)) if possible.
614  */
615 static int
616 findslot (char *line_name, char *host_name, int addp, int slot)
617 {
618         int     utmp;
619         struct  utmp entry;
620         int     found = 0;
621         int     freeslot = -1;
622
623         syserr(utmp = open (utmp_file, O_RDONLY), "open utmp");
624
625         /*
626          * first, try to locate a previous entry for this display
627          * also record location of a free slots in case we need a new one
628          */
629         syserr ((int) lseek (utmp, (long) slot * sizeof (struct utmp), 0), "lseek");
630
631         if (!host_name)
632                 host_name = "";
633
634         while (read (utmp, (char *) &entry, sizeof (entry)) == sizeof (entry)) {
635                 if (strncmp(entry.ut_line, line_name,
636                         sizeof(entry.ut_line)) == 0
637 #ifdef HAVE_STRUCT_UTMP_UT_HOST
638                     &&
639                     strncmp(entry.ut_host, host_name,
640                         sizeof(entry.ut_host)) == 0
641 #endif
642                    ) {
643                         found = 1;
644                         break;
645                 }
646                 if (freeslot < 0 && *entry.ut_name == '\0')
647                         freeslot = slot;
648                 ++slot;
649         }
650
651         close (utmp);
652
653         if (found)
654                 return slot;
655         else if (!addp)
656                 return 0;       /* trying to delete a non-existing entry */
657         else if (freeslot < 0)
658                 return slot;    /* first slot past current entries */
659         else
660                 return freeslot;
661 }
662 #endif