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