ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/libptytty/src/logging.C
Revision: 1.71
Committed: Mon May 24 14:22:50 2021 UTC (5 years, 4 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.70: +139 -169 lines
Log Message:
Stop using utmp if utmpx is available

This commit changes ptytty to use only utmpx on systems where both
utmpx and utmp are available, as utmp is generally deprecated and
pointless to use on these, glibc being the exception. The commit also
refactors code to reduce the amount of ifdeffery.

File Contents

# Content
1 /*----------------------------------------------------------------------*
2 * File: logging.C
3 *----------------------------------------------------------------------*
4 *
5 * All portions of code are copyright by their respective author/s.
6 * Copyright (c) 1992 John Bovey <jdb@ukc.ac.uk>
7 * - original version
8 * Copyright (c) 1993 lipka
9 * Copyright (c) 1993 Brian Stempien <stempien@cs.wmich.edu>
10 * Copyright (c) 1995 Raul Garcia Garcia <rgg@tid.es>
11 * Copyright (c) 1995 Piet W. Plomp <piet@idefix.icce.rug.nl>
12 * Copyright (c) 1997 Raul Garcia Garcia <rgg@tid.es>
13 * Copyright (c) 1998-2001 Geoff Wing <gcw@pobox.com>
14 * - extensive modifications
15 * Copyright (c) 1999 D J Hawkey Jr <hawkeyd@visi.com>
16 * - lastlog support
17 * Copyright (c) 2004-2006 Marc Lehmann <schmorp@schmorp.de>
18 * Copyright (c) 2006-2021 Emanuele Giaquinta <e.giaquinta@glauco.it>
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33 *----------------------------------------------------------------------*/
34
35 #include "config.h"
36
37 #include "ptytty.h"
38
39 #include <pwd.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <sys/types.h>
43 #include <time.h>
44 #include <unistd.h>
45
46 static void
47 fill_id (char *id, const char *line, size_t id_size)
48 {
49 size_t len = strlen (line);
50
51 if (len > id_size)
52 line += len - id_size;
53 strncpy (id, line, id_size);
54 }
55
56 /*
57 * BSD style utmp entry
58 * ut_line, ut_name, ut_host, ut_time
59 * SYSV style utmp (and utmpx) entry
60 * ut_user, ut_id, ut_line, ut_pid, ut_type, ut_exit, ut_time
61 */
62
63 #if defined(USE_UTMPX)
64
65 #include <utmpx.h>
66
67 #if !defined(WTMPX_FILE)
68 # if defined(_PATH_WTMPX)
69 # define WTMPX_FILE _PATH_WTMPX
70 # elif defined(PT_WTMPX_FILE)
71 # define WTMPX_FILE PT_WTMPX_FILE
72 # endif
73 #endif
74
75 #if !defined(LASTLOGX_FILE)
76 # if defined(_PATH_LASTLOGX)
77 # define LASTLOGX_FILE _PATH_LASTLOGX
78 # elif defined(PT_LASTLOGX_FILE)
79 # define LASTLOGX_FILE PT_LASTLOGX_FILE
80 # endif
81 #endif
82
83 #ifdef LASTLOG_SUPPORT
84 static void
85 update_lastlog (const char *pty, const char *host)
86 {
87 # if defined(HAVE_STRUCT_LASTLOGX) && defined(HAVE_UPDLASTLOGX)
88 struct lastlogx llx;
89
90 memset (&llx, 0, sizeof (llx));
91 llx.ll_tv.tv_sec = time (NULL);
92 llx.ll_tv.tv_usec = 0;
93 strncpy (llx.ll_line, pty, sizeof (llx.ll_line));
94 strncpy (llx.ll_host, host, sizeof (llx.ll_host));
95 updlastlogx (LASTLOGX_FILE, getuid (), &llx);
96 # endif
97 }
98 #endif
99
100 static void
101 fill_utmpx (struct utmpx *utx, bool login, int pid, const char *line, const char *user, const char *host)
102 {
103 memset (utx, 0, sizeof (struct utmpx));
104
105 // posix says that ut_line is not meaningful for DEAD_PROCESS
106 // records, but most implementations of last use ut_line to
107 // associate records in wtmp file
108 strncpy (utx->ut_line, line, sizeof (utx->ut_line));
109 fill_id (utx->ut_id, line, sizeof (utx->ut_id));
110 utx->ut_pid = pid;
111 utx->ut_type = login ? USER_PROCESS : DEAD_PROCESS;
112 utx->ut_tv.tv_sec = time (NULL);
113 utx->ut_tv.tv_usec = 0;
114
115 // posix says that ut_user is not meaningful for DEAD_PROCESS
116 // records, but solaris utmp_update helper requires that the ut_user
117 // field of a DEAD_PROCESS entry matches the one of an existing
118 // USER_PROCESS entry for the same line, if any
119 strncpy (utx->ut_user, user, sizeof (utx->ut_user));
120
121 #ifdef HAVE_UTMPX_HOST
122 if (login)
123 strncpy (utx->ut_host, host, sizeof (utx->ut_host));
124 #endif
125 }
126
127 void
128 ptytty_unix::log_session (bool login, const char *hostname)
129 {
130 struct passwd *pwent = getpwuid (getuid ());
131 const char *user = (pwent && pwent->pw_name) ? pwent->pw_name : "?";
132
133 const char *pty = name;
134
135 if (!strncmp (pty, "/dev/", 5))
136 pty += 5; /* skip /dev/ prefix */
137
138 struct utmpx *tmputx;
139 struct utmpx utx;
140 fill_utmpx (&utx, login, cmd_pid, pty, user, hostname);
141
142 setutxent ();
143 if (login || ((tmputx = getutxid (&utx)) && tmputx->ut_pid == cmd_pid))
144 pututxline (&utx);
145 endutxent ();
146
147 if (login_shell)
148 {
149 #if defined(WTMP_SUPPORT) && defined(HAVE_UPDWTMPX)
150 updwtmpx (WTMPX_FILE, &utx);
151 #endif
152
153 #ifdef LASTLOG_SUPPORT
154 if (login)
155 {
156 if (pwent)
157 update_lastlog (pty, hostname);
158 else
159 PTYTTY_WARN ("no entry in password file, not updating lastlog.\n");
160 }
161 #endif
162 }
163 }
164
165 #elif defined(USE_UTMP)
166
167 #include <utmp.h>
168 #ifdef HAVE_LASTLOG_H
169 # include <lastlog.h>
170 #endif
171
172 #if !defined(UTMP_FILE)
173 # if defined(_PATH_UTMP)
174 # define UTMP_FILE _PATH_UTMP
175 # elif defined(PT_UTMP_FILE)
176 # define UTMP_FILE PT_UTMP_FILE
177 # endif
178 #endif
179
180 #if !defined(WTMP_FILE)
181 # if defined(_PATH_WTMP)
182 # define WTMP_FILE _PATH_WTMP
183 # elif defined(PT_WTMP_FILE)
184 # define WTMP_FILE PT_WTMP_FILE
185 # endif
186 #endif
187
188 #if !defined(LASTLOG_FILE)
189 # if defined(_PATH_LASTLOG)
190 # define LASTLOG_FILE _PATH_LASTLOG
191 # elif defined(PT_LASTLOG_FILE)
192 # define LASTLOG_FILE PT_LASTLOG_FILE
193 # endif
194 #endif
195
196 #include <sys/stat.h>
197 #include <fcntl.h>
198 #include <errno.h>
199
200 static void
201 write_record (const char *path, off_t pos, const void *record, size_t size)
202 {
203 int fd = open (path, O_WRONLY);
204 if (fd >= 0)
205 {
206 pwrite (fd, record, size, pos * size);
207 close (fd);
208 }
209 }
210
211 /* ------------------------------------------------------------------------- */
212 /*
213 * Update a BSD style wtmp entry
214 */
215 #if defined(WTMP_SUPPORT) && !defined(HAVE_UPDWTMP)
216 static void
217 updwtmp (const char *fname, const struct utmp *ut)
218 {
219 int fd, gotlock, retry;
220 struct flock lck; /* fcntl locking scheme */
221 struct stat sbuf;
222
223 if ((fd = open (fname, O_WRONLY | O_APPEND, 0)) < 0)
224 return;
225
226 lck.l_whence = SEEK_END; /* start lock at current eof */
227 lck.l_len = 0; /* end at ``largest possible eof'' */
228 lck.l_start = 0;
229 lck.l_type = F_WRLCK; /* we want a write lock */
230
231 /* attempt lock with F_SETLK; F_SETLKW would cause a deadlock! */
232 for (retry = 10, gotlock = 0; retry--;)
233 if (fcntl (fd, F_SETLK, &lck) != -1)
234 {
235 gotlock = 1;
236 break;
237 }
238 else if (errno != EAGAIN && errno != EACCES)
239 break;
240
241 if (gotlock)
242 {
243 if (fstat (fd, &sbuf) == 0)
244 if (write (fd, ut, sizeof (struct utmp)) != sizeof (struct utmp))
245 ftruncate (fd, sbuf.st_size); /* remove bad writes */
246
247 lck.l_type = F_UNLCK; /* unlocking the file */
248 fcntl (fd, F_SETLK, &lck);
249 }
250
251 close (fd);
252 }
253 #endif
254
255 /* ------------------------------------------------------------------------- */
256 #ifdef LASTLOG_SUPPORT
257 static void
258 update_lastlog (const char *pty, const char *host)
259 {
260 # ifdef HAVE_STRUCT_LASTLOG
261 struct lastlog ll;
262
263 memset (&ll, 0, sizeof (ll));
264 ll.ll_time = time (NULL);
265 strncpy (ll.ll_line, pty, sizeof (ll.ll_line));
266 strncpy (ll.ll_host, host, sizeof (ll.ll_host));
267 write_record (LASTLOG_FILE, getuid (), &ll, sizeof (ll));
268 # endif /* HAVE_STRUCT_LASTLOG */
269 }
270 #endif /* LASTLOG_SUPPORT */
271
272 static void
273 fill_utmp (struct utmp *ut, bool login, int pid, const char *line, const char *user, const char *host)
274 {
275 memset (ut, 0, sizeof (struct utmp));
276
277 strncpy (ut->ut_line, line, sizeof (ut->ut_line));
278 #ifdef HAVE_UTMP_PID
279 fill_id (ut->ut_id, line, sizeof (ut->ut_id));
280 ut->ut_pid = pid;
281 ut->ut_type = login ? USER_PROCESS : DEAD_PROCESS;
282 #endif
283 ut->ut_time = time (NULL);
284
285 if (login)
286 {
287 #ifdef HAVE_UTMP_PID
288 strncpy (ut->ut_user, user, sizeof (ut->ut_user));
289 #else
290 strncpy (ut->ut_name, user, sizeof (ut->ut_name));
291 #endif
292 #ifdef HAVE_UTMP_HOST
293 strncpy (ut->ut_host, host, sizeof (ut->ut_host));
294 #endif
295 }
296 }
297
298 void
299 ptytty_unix::log_session (bool login, const char *hostname)
300 {
301 struct passwd *pwent = getpwuid (getuid ());
302 const char *user = (pwent && pwent->pw_name) ? pwent->pw_name : "?";
303
304 const char *pty = name;
305
306 if (!strncmp (pty, "/dev/", 5))
307 pty += 5; /* skip /dev/ prefix */
308
309 struct utmp *tmput;
310 struct utmp ut;
311 fill_utmp (&ut, login, cmd_pid, pty, user, hostname);
312
313 #ifdef HAVE_UTMP_PID
314 setutent ();
315 if (login || ((tmput = getutid (&ut)) && tmput->ut_pid == cmd_pid))
316 pututline (&ut);
317 endutent ();
318 #else
319 if (utmp_pos > 0)
320 write_record (UTMP_FILE, utmp_pos, &ut, sizeof (ut));
321 #endif
322
323 if (login_shell)
324 {
325 #ifdef WTMP_SUPPORT
326 updwtmp (WTMP_FILE, &ut);
327 #endif
328
329 #ifdef LASTLOG_SUPPORT
330 if (login)
331 {
332 if (pwent)
333 update_lastlog (pty, hostname);
334 else
335 PTYTTY_WARN ("no entry in password file, not updating lastlog.\n");
336 }
337 #endif
338 }
339 }
340
341 #endif
342