1 /* This file is part of GNU Pies.
2    Copyright (C) 2013-2020 Sergey Poznyakoff
3 
4    GNU Pies is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3, or (at your option)
7    any later version.
8 
9    GNU Pies is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with GNU Pies.  If not, see <http://www.gnu.org/licenses/>. */
16 
17 #include "pies.h"
18 #include <fcntl.h>
19 #include <sys/utsname.h>
20 #include <paths.h>
21 
22 #ifdef  HAVE_UTMPX_H
23 # include <utmpx.h>
24 typedef struct utmpx UTMPX;
25 # if HAVE_UPDWTMPX
26 #  define pies_updwtmpx updwtmpx
27 # endif
28 # define GETUTXID getutxid
29 # if defined HAVE_STRUCT_UTMPX_UT_NAME
30 #  define UT_NAME(u) ((u)->ut_name)
31 # elif defined HAVE_STRUCT_UTMPX_UT_USER
32 #  define UT_NAME(u) ((u)->ut_user)
33 # endif
34 #else
35 # include <utmp.h>
36 typedef struct utmp UTMPX;
37 # if defined HAVE_STRUCT_UTMP_UT_NAME
38 #  define UT_NAME(u) ((u)->ut_name)
39 # elif defined HAVE_STRUCT_UTMP_UT_USER
40 #  define UT_NAME(u) ((u)->ut_user)
41 # endif
42 # if HAVE_UPDWTMP
43 #  define pies_updwtmpx updwtmp
44 # endif
45 # define GETUTXID getutid
46 # define setutxent setutent
47 # define pututxline pututline
48 # define endutxent endutent
49 #endif
50 
51 #ifndef WTMPX_FILE
52 # define WTMPX_FILE _PATH_WTMPX
53 #endif
54 #ifndef UTMPX_FILE
55 # define UTMPX_FILE _PATH_UTMPX
56 #endif
57 
58 #if !defined(UTMPX_FILE) || !defined(WTMPX_FILE)
59 # if !defined(UTMP_FILE) || !defined(WTMP_FILE)
60 #  ifndef  HAVE_UTMPX_H
61 #   include <utmp.h>
62 #  endif
63 #  if !defined(UTMP_FILE)
64 #   if !defined(_PATH_UTMP)
65 #    error "None of UTMPX_FILE, UTMP_FILE or _PATH_UTMP defined"
66 #   else
67 #    define UTMP_FILE _PATH_UTMP
68 #   endif
69 #  endif
70 #  if !defined(WTMP_FILE)
71 #   if !defined(_PATH_WTMP)
72 #    error "None of WTMPX_FILE, WTMP_FILE or _PATH_WTMP defined"
73 #   else
74 #    define WTMP_FILE _PATH_WTMP
75 #   endif
76 #  endif
77 # endif
78 # if !defined(UTMPX_FILE)
79 #  define UTMPX_FILE UTMP_FILE
80 # endif
81 # if !defined(WTMPX_FILE)
82 #  define WTMPX_FILE WTMP_FILE
83 # endif
84 #endif
85 
86 #ifndef pies_updwtmpx
87 static void
pies_updwtmpx(const char * wtmp_file,const UTMPX * ut)88 pies_updwtmpx (const char *wtmp_file, const UTMPX *ut)
89 {
90   int fd = open (wtmp_file, O_WRONLY|O_APPEND);
91   if (fd == -1)
92     return;
93   if (write (fd, ut, sizeof (*ut)) == -1)
94     logmsg (LOG_ERR, "write %s: %s", wtmp_file, strerror (errno));
95   close (fd);
96 }
97 #endif
98 
99 static UTMPX *
pies_getutxid(const UTMPX * ut)100 pies_getutxid (const UTMPX *ut)
101 {
102   static UTMPX tmp;
103   memcpy (&tmp, ut, sizeof (*ut));
104   return GETUTXID (&tmp);
105 }
106 
107 void
fill_utmp(UTMPX * utmp,int type,const char * user,const char * id,pid_t pid,const char * line)108 fill_utmp (UTMPX *utmp,
109 	   int type, const char *user, const char *id, pid_t pid,
110 	   const char *line)
111 {
112   memset (utmp, 0, sizeof (*utmp));
113 #if defined(HAVE_STRUCT_UTMP_UT_TV) || defined(HAVE_STRUCT_UTMPX_UT_TV)
114   {
115     struct timeval tv;
116     gettimeofday (&tv, 0);
117     utmp->ut_tv.tv_sec = tv.tv_sec;
118     utmp->ut_tv.tv_usec = tv.tv_usec;
119   }
120 #elif defined(HAVE_STRUCT_UTMP_UT_TIME) || defined(HAVE_STRUCT_UTMPX_UT_TIME)
121   time (&utmp->ut_time);
122 #endif
123   utmp->ut_type = type;
124   strncpy (UT_NAME (utmp), user, sizeof (UT_NAME (utmp)));
125   strncpy (utmp->ut_id, id, sizeof (utmp->ut_id));
126   utmp->ut_pid  = pid;
127   strncpy (utmp->ut_line, line, sizeof(utmp->ut_line));
128 #if defined(HAVE_STRUCT_UTMP_UT_HOST) || defined(HAVE_STRUCT_UTMPX_UT_HOST)
129   {
130     struct utsname uts;
131     if (uname (&uts) == 0)
132       strncpy (utmp->ut_host, uts.release, sizeof(utmp->ut_host));
133   }
134 #endif
135 }
136 
137 void
write_wtmpx(int type,const char * user,const char * id,pid_t pid,const char * line)138 write_wtmpx (int type, const char *user, const char *id, pid_t pid,
139 	     const char *line)
140 {
141   UTMPX utmp;
142   static int wtmpxreboot = 0;
143 
144   debug (2, (_("cannot open %s for writing"), WTMPX_FILE));
145   if (access (WTMPX_FILE, W_OK))
146     {
147       if (type == BOOT_TIME)
148 	wtmpxreboot++;
149       return;
150     }
151 
152   if (wtmpxreboot)
153     {
154       write_wtmpx (BOOT_TIME, "reboot", "~~", 0, "~");
155       --wtmpxreboot;
156     }
157   fill_utmp (&utmp, type, user, id, pid, line);
158   pies_updwtmpx (WTMPX_FILE, &utmp);
159 }
160 
161 void
write_utmpx(int type,const char * user,const char * id,pid_t pid,const char * line)162 write_utmpx (int type, const char *user, const char *id, pid_t pid,
163 	     const char *line)
164 {
165   UTMPX utmp;
166   static int utmpreboot = 0;
167 
168   if (access (UTMPX_FILE, W_OK))
169     {
170       debug (1, (_("cannot open %s for writing"), UTMPX_FILE));
171       if (type == BOOT_TIME)
172 	utmpreboot++;
173       return;
174     }
175 
176   if (utmpreboot)
177     {
178       write_utmpx (BOOT_TIME, "reboot", "~~", 0, "~");
179       --utmpreboot;
180     }
181   fill_utmp (&utmp, type, user, id, pid, line);
182 
183   if (type == DEAD_PROCESS)
184     {
185       UTMPX *p = pies_getutxid (&utmp);
186       if (p)
187 	strncpy (utmp.ut_line, p->ut_line, sizeof (utmp.ut_line));
188     }
189   setutxent ();
190   pututxline (&utmp);
191   endutxent ();
192 }
193 
194 void
sysvinit_acct(int what,const char * user,const char * id,pid_t pid,const char * line)195 sysvinit_acct (int what, const char *user, const char *id, pid_t pid,
196 	       const char *line)
197 {
198   static int types[] = {
199     BOOT_TIME,
200     RUN_LVL,
201     INIT_PROCESS,
202     DEAD_PROCESS
203   };
204   write_utmpx (types[what], user, id, pid, line);
205   write_wtmpx (types[what], user, id, pid, line);
206 }
207