Merge branch 'devel/upgrade' into tizen
[platform/upstream/sessreg.git] / 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 #ifdef USE_UTMPX
94 #ifdef HAVE_UPDWTMPX
95 static const char *wtmpx_file = NULL;
96 #endif
97 #ifdef HAVE_UTMPXNAME
98 static const char *utmpx_file = NULL;
99 #endif
100 #endif
101
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,
134                          "%s: usage %s {-a -d} [-w wtmp-file] [-u utmp-file]"
135 #ifdef USE_LASTLOG
136                          " [-L lastlog-file]"
137 #endif
138                          "\n"
139                          "             [-t ttys-file] [-l line-name] [-h host-name] [-V]\n"
140                          "             [-s slot-number] [-x servers-file] user-name\n",
141                          program_name, program_name);
142                 exit (1);
143         }
144         return x;
145 }
146
147 static char *
148 getstring (char ***avp, int *flagp)
149 {
150         char    **a = *avp;
151
152         usage ((*flagp)++);
153         if (*++*a)
154                 return *a;
155         ++a;
156         usage (!*a);
157         *avp = a;
158         return *a;
159 }
160
161 #if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE)
162 static int
163 syserr (int x, const char *s)
164 {
165         if (x == -1) {
166                 perror (s);
167                 exit (1);
168         }
169         return x;
170 }
171 #endif
172
173 static int
174 sysnerr (int x, const char *s)
175 {
176         if (x == 0) {
177                 perror (s);
178                 exit (1);
179         }
180         return x;
181 }
182
183 int
184 main (int argc, char **argv)
185 {
186 #if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE)
187         int             utmp;
188 #endif
189 #ifndef USE_UTMPX
190         int             wtmp;
191 #endif
192         time_t          current_time;
193 #ifdef USE_UTMP
194         struct utmp     utmp_entry;
195 #endif
196 #ifdef USE_UTMPX
197         struct utmpx    utmpx_entry;
198 #endif
199         char *          line = NULL;
200
201         program_name = argv[0];
202         while (*++argv && **argv == '-') {
203                 switch (*++*argv) {
204                 case 'w':
205                         wtmp_file = getstring (&argv, &wflag);
206                         if (!strcmp (wtmp_file, "none"))
207                                 wtmp_none = 1;
208                         break;
209                 case 'u':
210                         utmp_file = getstring (&argv, &uflag);
211                         if (!strcmp (utmp_file, "none"))
212                                 utmp_none = 1;
213                         break;
214 #ifdef USE_LASTLOG
215                 case 'L':
216                         llog_file = getstring (&argv, &Lflag);
217                         if (!strcmp (llog_file, "none"))
218                                 llog_none = 1;
219                         break;
220 #endif
221                 case 't':
222                         ttys_file = getstring (&argv, &tflag);
223                         break;
224                 case 'l':
225                         line = getstring (&argv, &lflag);
226                         break;
227                 case 'h':
228                         host_name = getstring (&argv, &hflag);
229                         break;
230                 case 's':
231 #if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE)
232                         slot_number = atoi (getstring (&argv, &sflag));
233 #endif
234                         break;
235                 case 'x':
236                         xservers_file = getstring (&argv, &xflag);
237                         break;
238                 case 'a':
239                         aflag++;
240                         break;
241                 case 'd':
242                         dflag++;
243                         break;
244                 case 'V':
245                         printf("%s\n", PACKAGE_STRING);
246                         exit (0);
247                 default:
248                         usage (1);
249                 }
250         }
251         usage (!(user_name = *argv++));
252         usage (*argv != NULL);
253         /*
254          * complain if neither aflag nor dflag are set,
255          * or if both are set.
256          */
257         usage (!(aflag ^ dflag));
258         usage (xflag && !lflag);
259         /* set up default file names */
260         if (!wflag) {
261                 wtmp_file = WTMP_FILE;
262 #if defined(USE_UTMPX) && defined(HAVE_UPDWTMPX)
263                 wtmpx_file = WTMPX_FILE;
264 #endif
265         }
266         if (!uflag) {
267                 utmp_file = UTMP_FILE;
268 #if defined(USE_UTMPX) && defined(HAVE_UTMPXNAME)
269                 utmpx_file = UTMPX_FILE;
270 #endif
271         }
272 #ifdef USE_LASTLOG
273         if (!Lflag)
274                 llog_file = LLOG_FILE;
275 #endif
276 #if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE)
277         if (!tflag)
278                 ttys_file = TTYS_FILE;
279         if (!sflag && !utmp_none) {
280                 if (xflag)
281                         sysnerr (slot_number = Xslot (ttys_file, xservers_file, line, host_name, aflag), "Xslot");
282                 else
283                         sysnerr (slot_number = ttyslot (), "ttyslot");
284         }
285 #endif
286         if (!lflag) {
287                 sysnerr ((line = ttyname (0)) != NULL, "ttyname");
288                 if (strncmp(line, "/dev/", 5) == 0)
289                         line += 5;
290         }
291         time (&current_time);
292 #ifdef USE_UTMP
293         set_utmp (&utmp_entry, line, user_name, host_name, current_time, aflag);
294 #endif
295
296 #ifdef USE_UTMPX
297         /* need to set utmpxname() before calling set_utmpx() for
298            UtmpxIdOpen to work */
299 # ifdef HAVE_UTMPXNAME
300         if (utmpx_file != NULL) {
301                 utmpxname (utmpx_file);
302         }
303 # endif
304         set_utmpx (&utmpx_entry, line, user_name,
305                    host_name, current_time, aflag);
306 #endif
307
308         if (!utmp_none) {
309 #ifdef USE_UTMPX
310 # ifdef HAVE_UTMPXNAME
311                 if (utmpx_file != NULL)
312 # endif
313                 {
314                         setutxent ();
315                         (void) getutxid (&utmpx_entry);
316                         pututxline (&utmpx_entry);
317                         endutxent ();
318                 }
319 #endif
320 #ifdef USE_UTMP
321 # ifdef HAVE_PUTUTLINE
322                 utmpname (utmp_file);
323                 setutent ();
324                 (void) getutid (&utmp_entry);
325                 pututline (&utmp_entry);
326                 endutent ();
327 # else
328                 utmp = open (utmp_file, O_RDWR);
329                 if (utmp != -1) {
330                         syserr ((int) lseek (utmp, (long) slot_number * sizeof (struct utmp), 0), "lseek");
331                         sysnerr (write (utmp, (char *) &utmp_entry, sizeof (utmp_entry))
332                                         == sizeof (utmp_entry), "write utmp entry");
333                         close (utmp);
334                 }
335 # endif
336 #endif /* USE_UTMP */
337         }
338         if (!wtmp_none) {
339 #ifdef USE_UTMPX
340 # ifdef HAVE_UPDWTMPX
341                 if (wtmpx_file != NULL) {
342                         updwtmpx(wtmpx_file, &utmpx_entry);
343                 }
344 # endif
345 #else
346                 wtmp = open (wtmp_file, O_WRONLY|O_APPEND);
347                 if (wtmp != -1) {
348                         sysnerr (write (wtmp, (char *) &utmp_entry, sizeof (utmp_entry))
349                                         == sizeof (utmp_entry), "write wtmp entry");
350                         close (wtmp);
351                 }
352 #endif
353         }
354 #ifdef USE_LASTLOG
355         if (aflag && !llog_none) {
356                 int llog;
357                 struct passwd *pwd = getpwnam(user_name);
358
359                 sysnerr( pwd != NULL, "get user id");
360                 llog = open (llog_file, O_RDWR);
361
362                 if (llog != -1) {
363                         struct lastlog ll;
364
365                         sysnerr (lseek(llog, (long) (pwd->pw_uid*sizeof(ll)), 0)
366                                         != -1, "seeking lastlog entry");
367                         memset(&ll, 0, sizeof(ll));
368                         ll.ll_time = current_time;
369                         if (line)
370                          (void) strncpy (ll.ll_line, line, sizeof (ll.ll_line));
371                         if (host_name)
372                          (void) strncpy (ll.ll_host, host_name, sizeof (ll.ll_host));
373
374                         sysnerr (write (llog, (char *) &ll, sizeof (ll))
375                                         == sizeof (ll), "write lastlog entry");
376                         close (llog);
377                 }
378         }
379 #endif
380         return 0;
381 }
382
383 /*
384  * fill in the appropriate records of the utmp entry
385  */
386
387 #ifdef USE_UTMP
388 static void
389 set_utmp (struct utmp *u, char *line, char *user, char *host, time_t date, int addp)
390 {
391         memset (u, 0, sizeof (*u));
392         if (line)
393                 (void) strncpy (u->ut_line, line, sizeof (u->ut_line));
394         else
395                 memset (u->ut_line, 0, sizeof (u->ut_line));
396         if (addp && user)
397                 (void) strncpy (u->ut_name, user, sizeof (u->ut_name));
398         else
399                 memset (u->ut_name, 0, sizeof (u->ut_name));
400 #ifdef HAVE_STRUCT_UTMP_UT_ID
401         if (line) {
402                 size_t  i;
403                 /*
404                  * this is a bit crufty, but
405                  * follows the apparent conventions in
406                  * the ttys file.  ut_id is only 4 bytes
407                  * long, and the last 4 bytes of the line
408                  * name are written into it, left justified.
409                  */
410                 i = strlen (line);
411                 if (i >= sizeof (u->ut_id))
412                         i -= sizeof (u->ut_id);
413                 else
414                         i = 0;
415                 (void) strncpy (u->ut_id, line + i, sizeof (u->ut_id));
416         } else
417                 memset (u->ut_id, 0, sizeof (u->ut_id));
418 #endif
419 #ifdef HAVE_STRUCT_UTMP_UT_PID
420         if (addp)
421                 u->ut_pid = getppid ();
422         else
423                 u->ut_pid = 0;
424 #endif
425 #ifdef HAVE_STRUCT_UTMP_UT_TYPE
426         if (addp)
427                 u->ut_type = USER_PROCESS;
428         else
429                 u->ut_type = DEAD_PROCESS;
430 #endif
431 #ifdef HAVE_STRUCT_UTMP_UT_HOST
432         if (addp && host)
433                 (void) strncpy (u->ut_host, host, sizeof (u->ut_host));
434         else
435                 memset (u->ut_host, 0, sizeof (u->ut_host));
436 #endif
437         u->ut_time = date;
438 }
439 #endif /* USE_UTMP */
440
441 #ifdef USE_UTMPX
442 static int
443 UtmpxIdOpen( char *utmpId )
444 {
445         struct utmpx *u;        /* pointer to entry in utmp file           */
446         int    status = 1;      /* return code                             */
447
448         setutxent();
449
450         while ( (u = getutxent()) != NULL ) {
451
452                 if ( (strncmp(u->ut_id, utmpId, 4) == 0 ) &&
453                      u->ut_type != DEAD_PROCESS ) {
454
455                         status = 0;
456                         break;
457                 }
458         }
459
460         endutxent();
461         return (status);
462 }
463
464 static void
465 set_utmpx (struct utmpx *u, const char *line, const char *user,
466            const char *host, time_t date, int addp)
467 {
468         static const char letters[] =
469                "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
470
471         if (line)
472         {
473                 if(strcmp(line, ":0") == 0)
474                         (void) strcpy(u->ut_line, "console");
475                 else
476                         (void) strncpy (u->ut_line, line, sizeof (u->ut_line));
477
478                 strncpy(u->ut_host, line, sizeof(u->ut_host));
479 #ifdef HAVE_STRUCT_UTMPX_UT_SYSLEN
480                 u->ut_syslen = strlen(line);
481 #endif
482         }
483         else
484                 memset (u->ut_line, 0, sizeof (u->ut_line));
485         if (addp && user)
486                 (void) strncpy (u->ut_user, user, sizeof (u->ut_user));
487         else
488                 memset (u->ut_user, 0, sizeof (u->ut_user));
489
490         if (line) {
491                 size_t  i;
492                 /*
493                  * this is a bit crufty, but
494                  * follows the apparent conventions in
495                  * the ttys file.  ut_id is only 4 bytes
496                  * long, and the last 4 bytes of the line
497                  * name are written into it, left justified.
498                  */
499                 i = strlen (line);
500                 if (i >= sizeof (u->ut_id))
501                         i -= sizeof (u->ut_id);
502                 else
503                         i = 0;
504                 (void) strncpy (u->ut_id, line + i, sizeof (u->ut_id));
505
506                 /* make sure there is no entry using identical ut_id */
507                 if (!UtmpxIdOpen(u->ut_id) && addp) {
508                         int limit = sizeof(letters) - 1;
509                         int t = 0;
510
511                         u->ut_id[1] = line[i];
512                         u->ut_id[2] = line[i+1];
513                         u->ut_id[3] = line[i+2];
514                         do {
515                                 u->ut_id[0] = letters[t];
516                                 t++;
517                         } while (!UtmpxIdOpen(u->ut_id) && (t < limit));
518                 }
519                 if (!addp && strstr(line, ":") != NULL) {
520                         struct utmpx *tmpu;
521
522                         while ( (tmpu = getutxent()) != NULL ) {
523                                 if ( (strcmp(tmpu->ut_host, line) == 0 ) &&
524                                         tmpu->ut_type != DEAD_PROCESS ) {
525                                         strncpy(u->ut_id, tmpu->ut_id,
526                                                 sizeof(u->ut_id));
527                                         break;
528                                 }
529                         }
530                         endutxent();
531                 }
532         } else
533                 memset (u->ut_id, 0, sizeof (u->ut_id));
534
535         if (addp) {
536                 u->ut_pid = getppid ();
537                 u->ut_type = USER_PROCESS;
538         } else {
539                 u->ut_pid = 0;
540                 u->ut_type = DEAD_PROCESS;
541         }
542         u->ut_tv.tv_sec = date;
543         u->ut_tv.tv_usec = 0;
544 }
545 #endif /* USE_UTMPX */
546
547 #if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE)
548 /*
549  * compute the slot-number for an X display.  This is computed
550  * by counting the lines in /etc/ttys and adding the line-number
551  * that the display appears on in Xservers.  This is a poor
552  * design, but is limited by the non-existant interface to utmp.
553  * If host_name is non-NULL, assume it contains the display name,
554  * otherwise use the tty_line argument (i.e., the tty name).
555  */
556
557 static int
558 Xslot (char *ttys_file, char *servers_file, char *tty_line, char *host_name,
559        int addp)
560 {
561         FILE    *ttys, *servers;
562         int     c;
563         int     slot = 1;
564         int     column0 = 1;
565         char    servers_line[1024];
566         char    disp_name[512];
567         int     len;
568         char    *pos;
569
570         /* remove screen number from the display name */
571         memset(disp_name, 0, sizeof(disp_name));
572         strncpy(disp_name, host_name ? host_name : tty_line, sizeof(disp_name)-1);
573         pos = strrchr(disp_name, ':');
574         if (pos) {
575                 pos = strchr(pos, '.');
576                 if (pos)
577                         *pos = '\0';
578         }
579         sysnerr ((int)(long)(ttys = fopen (ttys_file, "r")), ttys_file);
580         while ((c = getc (ttys)) != EOF)
581                 if (c == '\n') {
582                         ++slot;
583                         column0 = 1;
584                 } else
585                         column0 = 0;
586         if (!column0)
587                 ++slot;
588         (void) fclose (ttys);
589         sysnerr ((int)(long)(servers = fopen (servers_file, "r")), servers_file);
590
591         len = strlen (disp_name);
592         column0 = 1;
593         while (fgets (servers_line, sizeof (servers_line), servers)) {
594                 if (column0 && *servers_line != '#') {
595                         if (!strncmp (disp_name, servers_line, len) &&
596                             (servers_line[len] == ' ' ||
597                              servers_line[len] == '\t'))
598                                 return slot;
599                         ++slot;
600                 }
601                 if (servers_line[strlen(servers_line)-1] != '\n')
602                         column0 = 0;
603                 else
604                         column0 = 1;
605         }
606         /*
607          * display not found in Xservers file - allocate utmp entry dinamically
608          */
609         return findslot (tty_line, host_name, addp, slot);
610 }
611
612 /*
613  * find a free utmp slot for the X display.  This allocates a new entry
614  * past the regular tty entries if necessary, reusing existing entries
615  * (identified by (line,hostname)) if possible.
616  */
617 static int
618 findslot (char *line_name, char *host_name, int addp, int slot)
619 {
620         int     utmp;
621         struct  utmp entry;
622         int     found = 0;
623         int     freeslot = -1;
624
625         syserr(utmp = open (utmp_file, O_RDONLY), "open utmp");
626
627         /*
628          * first, try to locate a previous entry for this display
629          * also record location of a free slots in case we need a new one
630          */
631         syserr ((int) lseek (utmp, (long) slot * sizeof (struct utmp), 0), "lseek");
632
633         if (!host_name)
634                 host_name = "";
635
636         while (read (utmp, (char *) &entry, sizeof (entry)) == sizeof (entry)) {
637                 if (strncmp(entry.ut_line, line_name,
638                         sizeof(entry.ut_line)) == 0
639 #ifdef HAVE_STRUCT_UTMP_UT_HOST
640                     &&
641                     strncmp(entry.ut_host, host_name,
642                         sizeof(entry.ut_host)) == 0
643 #endif
644                    ) {
645                         found = 1;
646                         break;
647                 }
648                 if (freeslot < 0 && *entry.ut_name == '\0')
649                         freeslot = slot;
650                 ++slot;
651         }
652
653         close (utmp);
654
655         if (found)
656                 return slot;
657         else if (!addp)
658                 return 0;       /* trying to delete a non-existing entry */
659         else if (freeslot < 0)
660                 return slot;    /* first slot past current entries */
661         else
662                 return freeslot;
663 }
664 #endif