Simplify rxvt_temp_buf usage.
[dana/urxvt.git] / src / logging.C
1 // This file is part of libptytty. Do not make local modifications.
2 // http://software.schmorp.de/pkg/libptytty
3
4 /*----------------------------------------------------------------------*
5  * File:        logging.C
6  *----------------------------------------------------------------------*
7  *
8  * All portions of code are copyright by their respective author/s.
9  * Copyright (c) 1992      John Bovey <jdb@ukc.ac.uk>
10  *                              - original version
11  * Copyright (c) 1993      lipka
12  * Copyright (c) 1993      Brian Stempien <stempien@cs.wmich.edu>
13  * Copyright (c) 1995      Raul Garcia Garcia <rgg@tid.es>
14  * Copyright (c) 1995      Piet W. Plomp <piet@idefix.icce.rug.nl>
15  * Copyright (c) 1997      Raul Garcia Garcia <rgg@tid.es>
16  * Copyright (c) 1998-2001 Geoff Wing <gcw@pobox.com>
17  *                              - extensive modifications
18  * Copyright (c) 1999      D J Hawkey Jr <hawkeyd@visi.com>
19  *                              - lastlog support
20  * Copyright (c) 2004-2006 Marc Lehmann <pcg@goof.com>
21  * Copyright (c) 2006      Emanuele Giaquinta <e.giaquinta@glauco.it>
22  *
23  * This program is free software; you can redistribute it and/or modify
24  * it under the terms of the GNU General Public License as published by
25  * the Free Software Foundation; either version 2 of the License, or
26  * (at your option) any later version.
27  *
28  * This program is distributed in the hope that it will be useful,
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31  * GNU General Public License for more details.
32  *
33  * You should have received a copy of the GNU General Public License
34  * along with this program; if not, write to the Free Software
35  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36  *----------------------------------------------------------------------*/
37
38 #include "../config.h"
39
40 #include "ptytty.h"
41
42 #if UTMP_SUPPORT
43
44 #include <cstdio>
45 #include <cstring>
46
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <fcntl.h>
50 #include <unistd.h>
51 #include <time.h>
52 #include <errno.h>
53
54 /*
55  * BSD style utmp entry
56  *      ut_line, ut_name, ut_host, ut_time
57  * SYSV style utmp (and utmpx) entry
58  *      ut_user, ut_id, ut_line, ut_pid, ut_type, ut_exit, ut_time
59  */
60
61 /* ------------------------------------------------------------------------- */
62 /*
63  * Write a BSD style utmp entry
64  */
65 #if defined(HAVE_STRUCT_UTMP) && !defined(HAVE_UTMP_PID)
66 static int
67 write_bsd_utmp (int utmp_pos, struct utmp *wu)
68 {
69   int             fd;
70
71   if (utmp_pos <= 0 || (fd = open (UTMP_FILE, O_WRONLY)) == -1)
72     return 0;
73
74   if (lseek (fd, (off_t) (utmp_pos * sizeof (struct utmp)), SEEK_SET) != -1)
75     write (fd, wu, sizeof (struct utmp));
76   close (fd);
77   return 1;
78 }
79 #endif
80
81 /* ------------------------------------------------------------------------- */
82 /*
83  * Update a BSD style wtmp entry
84  */
85 #if defined(WTMP_SUPPORT) && !defined(HAVE_UPDWTMP) && defined(HAVE_STRUCT_UTMP)
86 static void
87 update_wtmp (const char *fname, const struct utmp *putmp)
88 {
89   int             fd, gotlock, retry;
90   struct flock    lck;  /* fcntl locking scheme */
91   struct stat     sbuf;
92
93   if ((fd = open (fname, O_WRONLY | O_APPEND, 0)) < 0)
94     return;
95
96   lck.l_whence = SEEK_END;      /* start lock at current eof */
97   lck.l_len = 0;                /* end at ``largest possible eof'' */
98   lck.l_start = 0;
99   lck.l_type = F_WRLCK; /* we want a write lock */
100
101   /* attempt lock with F_SETLK; F_SETLKW would cause a deadlock! */
102   for (retry = 10, gotlock = 0; retry--;)
103     if (fcntl (fd, F_SETLK, &lck) != -1)
104       {
105         gotlock = 1;
106         break;
107       }
108     else if (errno != EAGAIN && errno != EACCES)
109       break;
110   if (!gotlock)
111     {
112       /* give it up */
113       close (fd);
114       return;
115     }
116   if (fstat (fd, &sbuf) == 0)
117     if (write (fd, putmp, sizeof (struct utmp)) != sizeof (struct utmp))
118       ftruncate (fd, sbuf.st_size);     /* remove bad writes */
119
120   lck.l_type = F_UNLCK; /* unlocking the file */
121   fcntl (fd, F_SETLK, &lck);
122   close (fd);
123 }
124 #endif
125
126 /* ------------------------------------------------------------------------- */
127 #ifdef LASTLOG_SUPPORT
128 static void
129 update_lastlog (const char *fname, const char *pty, const char *host)
130 {
131 # if defined(HAVE_STRUCT_LASTLOGX) && defined(HAVE_UPDLASTLOGX)
132   struct lastlogx llx;
133 # endif
134 # ifdef HAVE_STRUCT_LASTLOG
135   int             fd;
136   struct lastlog  ll;
137   char            lastlogfile[256];
138   struct passwd  *pwent;
139   struct stat     st;
140 # endif
141
142 # if defined(HAVE_STRUCT_LASTLOGX) && defined(HAVE_UPDLASTLOGX)
143   memset (&llx, 0, sizeof (llx));
144   llx.ll_tv.tv_sec = time (NULL);
145   llx.ll_tv.tv_usec = 0;
146   strncpy (llx.ll_line, pty, sizeof (llx.ll_line));
147   strncpy (llx.ll_host, host, sizeof (llx.ll_host));
148   updlastlogx (LASTLOGX_FILE, getuid (), &llx);
149 # endif
150
151 # ifdef HAVE_STRUCT_LASTLOG
152   pwent = getpwuid (getuid ());
153   if (!pwent)
154     {
155       ptytty_warn ("no entry in password file, not updating lastlog.\n", 0);
156       return;
157     }
158
159   memset (&ll, 0, sizeof (ll));
160   ll.ll_time = time (NULL);
161   strncpy (ll.ll_line, pty, sizeof (ll.ll_line));
162   strncpy (ll.ll_host, host, sizeof (ll.ll_host));
163   if (stat (fname, &st) != 0)
164     return;
165   if (S_ISDIR (st.st_mode))
166     {
167       sprintf (lastlogfile, "%.*s/%.*s",
168                (int)(sizeof (lastlogfile) - sizeof (pwent->pw_name) - 2), fname,
169                (int)sizeof (pwent->pw_name),
170                (!pwent->pw_name || pwent->pw_name[0] == '\0') ? "unknown"
171                : pwent->pw_name);
172       if ((fd = open (lastlogfile, O_WRONLY | O_CREAT, 0644)) >= 0)
173         {
174           write (fd, &ll, sizeof (ll));
175           close (fd);
176         }
177     }
178   else if (S_ISREG (st.st_mode))
179     if ((fd = open (fname, O_RDWR)) != -1)
180       {
181         if (lseek (fd, (off_t) ((long)pwent->pw_uid * sizeof (ll)),
182                    SEEK_SET) != -1)
183           write (fd, &ll, sizeof (ll));
184         close (fd);
185       }
186 # endif /* HAVE_STRUCT_LASTLOG */
187 }
188 #endif /* LASTLOG_SUPPORT */
189
190 /* ------------------------------------------------------------------------- */
191
192 /*
193  * make and write utmp and wtmp entries
194  */
195 void
196 ptytty_unix::login (int cmd_pid, bool login_shell, const char *hostname)
197 {
198   const char *pty = name;
199
200   if (!pty || !*pty)
201     return;
202
203   this->cmd_pid     = cmd_pid;
204   this->login_shell = login_shell;
205
206 #ifdef HAVE_STRUCT_UTMP
207   struct utmp *ut = &this->ut;
208 #endif
209 #ifdef HAVE_STRUCT_UTMPX
210   struct utmpx *utx = &this->utx;
211 #endif
212   int i;
213   struct passwd *pwent = getpwuid (getuid ());
214   const char *name = (pwent && pwent->pw_name) ? pwent->pw_name : "?";
215
216   if (!strncmp (pty, "/dev/", 5))
217     pty += 5;           /* skip /dev/ prefix */
218
219 #if defined(HAVE_UTMP_PID) || defined(HAVE_STRUCT_UTMPX)
220   if (!strncmp (pty, "pty", 3) || !strncmp (pty, "tty", 3))
221     strncpy (ut_id, pty + 3, sizeof (ut_id));
222   else if (sscanf (pty, "pts/%d", &i) == 1)
223     sprintf (ut_id, "vt%02x", (i & 0xff));      /* sysv naming */
224   else
225     {
226       ptytty_warn ("can't parse tty name \"%s\", not adding utmp entry.\n", pty);
227       return;
228     }
229 #endif
230
231 #ifdef HAVE_STRUCT_UTMP
232   memset (ut, 0, sizeof (struct utmp));
233 # ifdef HAVE_UTMP_PID
234   setutent ();
235   strncpy (ut->ut_id, ut_id, sizeof (ut->ut_id));
236   ut->ut_type = DEAD_PROCESS;
237   getutid (ut);         /* position to entry in utmp file */
238 # endif
239 #endif
240
241 #ifdef HAVE_STRUCT_UTMPX
242   memset (utx, 0, sizeof (struct utmpx));
243   setutxent ();
244   strncpy (utx->ut_id, ut_id, sizeof (utx->ut_id));
245   utx->ut_type = DEAD_PROCESS;
246   getutxid (utx);               /* position to entry in utmp file */
247 #endif
248
249 #ifdef HAVE_STRUCT_UTMP
250   strncpy (ut->ut_line, pty, sizeof (ut->ut_line));
251 # ifdef HAVE_UTMP_HOST
252   strncpy (ut->ut_host, hostname, sizeof (ut->ut_host));
253 # endif
254   ut->ut_time = time (NULL);
255 # ifdef HAVE_UTMP_PID
256   strncpy (ut->ut_user, name, sizeof (ut->ut_user));
257   strncpy (ut->ut_id, ut_id, sizeof (ut->ut_id));
258   ut->ut_pid = cmd_pid;
259   ut->ut_type = USER_PROCESS;
260   pututline (ut);
261   endutent ();                  /* close the file */
262   utmp_pos = 0;
263 # else
264   strncpy (ut->ut_name, name, sizeof (ut->ut_name));
265 # endif
266 #endif
267
268 #ifdef HAVE_STRUCT_UTMPX
269   strncpy (utx->ut_line, pty, sizeof (utx->ut_line));
270   strncpy (utx->ut_user, name, sizeof (utx->ut_user));
271   strncpy (utx->ut_id, ut_id, sizeof (utx->ut_id));
272 # if HAVE_UTMPX_SESSION
273   utx->ut_session = getsid (0);
274 # endif
275   utx->ut_tv.tv_sec = time (NULL);
276   utx->ut_tv.tv_usec = 0;
277   utx->ut_pid = cmd_pid;
278 # ifdef HAVE_UTMPX_HOST
279   strncpy (utx->ut_host, hostname, sizeof (utx->ut_host));
280 #  if 0
281   {
282     char           *colon;
283
284     if ((colon = strrchr (ut->ut_host, ':')) != NULL)
285       *colon = '\0';
286   }
287 #  endif
288 # endif
289   utx->ut_type = USER_PROCESS;
290   pututxline (utx);
291   endutxent ();         /* close the file */
292   utmp_pos = 0;
293 #endif
294
295 #if defined(HAVE_STRUCT_UTMP) && !defined(HAVE_UTMP_PID)
296   {
297 # if 1
298     int fdstdin = dup (STDIN_FILENO);
299     dup2 (tty, STDIN_FILENO);
300
301     i = ttyslot ();
302     if (write_bsd_utmp (i, ut))
303       utmp_pos = i;
304
305     dup2 (fdstdin, STDIN_FILENO);
306     close (fdstdin);
307 # endif
308   }
309 #endif
310
311 #ifdef WTMP_SUPPORT
312 #ifdef LOG_ONLY_ON_LOGIN
313   if (login_shell)
314 #endif
315     {
316 # ifdef HAVE_STRUCT_UTMP
317 #  ifdef HAVE_UPDWTMP
318       updwtmp (WTMP_FILE, ut);
319 #  else
320       update_wtmp (WTMP_FILE, ut);
321 #  endif
322 # endif
323 # if defined(HAVE_STRUCT_UTMPX) && defined(HAVE_UPDWTMPX)
324       updwtmpx (WTMPX_FILE, utx);
325 # endif
326     }
327 #endif
328 #if defined(LASTLOG_SUPPORT) && defined(LASTLOG_FILE)
329 #ifdef LOG_ONLY_ON_LOGIN
330   if (login_shell)
331 #endif
332     update_lastlog (LASTLOG_FILE, pty, hostname);
333 #endif
334 }
335
336 /* ------------------------------------------------------------------------- */
337 /*
338  * remove utmp and wtmp entries
339  */
340 void
341 ptytty_unix::logout ()
342 {
343   if (!cmd_pid)
344     return;
345
346 #ifdef HAVE_STRUCT_UTMP
347   struct utmp *tmput, *ut = &this->ut;
348 #endif
349 #ifdef HAVE_STRUCT_UTMPX
350   struct utmpx *tmputx, *utx = &this->utx;
351 #endif
352
353 #ifdef HAVE_STRUCT_UTMP
354 # ifdef HAVE_UTMP_PID
355   memset (ut, 0, sizeof (struct utmp));
356   setutent ();
357   strncpy (ut->ut_id, this->ut_id, sizeof (ut->ut_id));
358   ut->ut_type = USER_PROCESS;
359   if ((tmput = getutid (ut)))           /* position to entry in utmp file */
360     ut = tmput;
361   ut->ut_type = DEAD_PROCESS;
362 # else
363   memset (ut->ut_name, 0, sizeof (ut->ut_name));
364 #  ifdef HAVE_UTMP_HOST
365   memset (ut->ut_host, 0, sizeof (ut->ut_host));
366 #  endif
367 # endif
368   ut->ut_time = time (NULL);
369 #endif
370
371 #ifdef HAVE_STRUCT_UTMPX
372   memset (utx, 0, sizeof (struct utmpx));
373   setutxent ();
374   strncpy (utx->ut_id, this->ut_id, sizeof (utx->ut_id));
375   utx->ut_type = USER_PROCESS;
376   if ((tmputx = getutxid (utx)))        /* position to entry in utmp file */
377     utx = tmputx;
378   utx->ut_type = DEAD_PROCESS;
379 # if HAVE_UTMPX_SESSION
380   utx->ut_session = getsid (0);
381 # endif
382   utx->ut_tv.tv_sec = time (NULL);
383   utx->ut_tv.tv_usec = 0;
384 #endif
385
386   /*
387    * Write ending wtmp entry
388    */
389 #ifdef WTMP_SUPPORT
390 #ifdef LOG_ONLY_ON_LOGIN
391   if (login_shell)
392 #endif
393     {
394 # ifdef HAVE_STRUCT_UTMP
395 #  ifdef HAVE_UPDWTMP
396       updwtmp (WTMP_FILE, ut);
397 #  else
398       update_wtmp (WTMP_FILE, ut);
399 #  endif
400 # endif
401 # if defined(HAVE_STRUCT_UTMPX) && defined(HAVE_UPDWTMPX)
402       updwtmpx (WTMPX_FILE, utx);
403 # endif
404     }
405 #endif
406
407   /*
408    * Write utmp entry
409    */
410 #ifdef HAVE_STRUCT_UTMP
411 # ifdef HAVE_UTMP_PID
412   if (ut->ut_pid == cmd_pid)
413     pututline (ut);
414   endutent ();
415 # else
416   memset (ut, 0, sizeof (struct utmp));
417   write_bsd_utmp (utmp_pos, ut);
418 # endif
419 #endif
420 #ifdef HAVE_STRUCT_UTMPX
421   if (utx->ut_pid == cmd_pid)
422     pututxline (utx);
423   endutxent ();
424 #endif
425
426   cmd_pid = 0;
427 }
428
429 #else
430 void
431 ptytty_unix::login (int cmd_pid, bool login_shell, const char *hostname)
432 {
433 }
434 #endif
435