source: trunk/src/sh_utmp.c @ 541

Last change on this file since 541 was 541, checked in by katerina, 3 years ago

Fix for ticket #433 (coding standardisation).

File size: 27.9 KB
Line 
1/* SAMHAIN file system integrity testing                                   */
2/* Copyright (C) 1999 Rainer Wichmann                                      */
3/*                                                                         */
4/*  This program is free software; you can redistribute it                 */
5/*  and/or modify                                                          */
6/*  it under the terms of the GNU General Public License as                */
7/*  published by                                                           */
8/*  the Free Software Foundation; either version 2 of the License, or      */
9/*  (at your option) any later version.                                    */
10/*                                                                         */
11/*  This program is distributed in the hope that it will be useful,        */
12/*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */
13/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
14/*  GNU General Public License for more details.                           */
15/*                                                                         */
16/*  You should have received a copy of the GNU General Public License      */
17/*  along with this program; if not, write to the Free Software            */
18/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
19
20#include "config_xor.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <fcntl.h>
28#include <errno.h>
29
30#ifdef HAVE_UTADDR
31#include <sys/socket.h>
32#include <netinet/in.h>
33#ifndef S_SPLINT_S
34#include <arpa/inet.h>
35#else
36#define AF_INET 2
37#endif
38#endif
39
40#ifdef SH_USE_UTMP
41
42#ifdef HAVE_UTMPX_H
43
44#ifdef S_SPLINT_S
45typedef pid_t __pid_t;
46#endif
47
48#include <utmpx.h>
49#define SH_UTMP_S utmpx
50#undef  ut_name
51#define ut_name ut_user
52#ifdef HAVE_UTXTIME
53#undef  ut_time
54#define ut_time        ut_xtime
55#else
56#undef  ut_time
57#define ut_time        ut_tv.tv_sec
58#endif
59
60#else
61#include <utmp.h>
62#define SH_UTMP_S utmp
63#endif
64
65
66#ifdef HAVE_PATHS_H
67#include <paths.h>
68#endif
69
70#undef  FIL__
71#define FIL__  _("sh_utmp.c")
72
73#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
74
75
76#include "samhain.h"
77#include "sh_utils.h"
78#include "sh_error.h"
79#include "sh_modules.h"
80#include "sh_utmp.h"
81#include "sh_pthread.h"
82#include "sh_inotify.h"
83
84SH_MUTEX_EXTERN(mutex_thread_nolog);
85
86#ifdef TM_IN_SYS_TIME
87#include <sys/time.h>
88#else
89#include <time.h>
90#endif
91
92#ifdef HAVE_UNISTD_H
93#include <unistd.h>
94#endif
95
96#ifdef HAVE_DIRENT_H
97#include <dirent.h>
98#define NAMLEN(dirent) sl_strlen((dirent)->d_name)
99#else
100#define dirent direct
101#define NAMLEN(dirent) (dirent)->d_namlen
102#ifdef HAVE_SYS_NDIR_H
103#include <sys/ndir.h>
104#endif
105#ifdef HAVE_SYS_DIR_H
106#include <sys/dir.h>
107#endif
108#ifdef HAVE_NDIR_H
109#include <ndir.h>
110#endif
111#endif
112
113#ifndef HAVE_LSTAT
114#define lstat stat
115#endif
116
117#ifndef UT_LINESIZE
118#ifndef __UT_LINESIZE
119#define UT_LINESIZE            12
120#else
121#define UT_LINESIZE __UT_LINESIZE
122#endif
123#endif
124
125#ifndef UT_NAMESIZE
126#ifndef __UT_NAMESIZE
127#define UT_NAMESIZE             8
128#else
129#define UT_NAMESIZE __UT_NAMESIZE
130#endif
131#endif
132
133#ifndef UT_HOSTSIZE
134#ifndef __UT_HOSTSIZE
135#define UT_HOSTSIZE            16
136#else
137#define UT_HOSTSIZE __UT_HOSTSIZE
138#endif
139#endif
140
141#ifdef HAVE_UTMPX_H
142
143#ifndef _PATH_UTMP
144#ifdef   UTMPX_FILE
145#define _PATH_UTMP   UTMPX_FILE
146#else 
147#error  You must define UTMPX_FILE in the file config.h
148#endif
149#endif
150#ifndef _PATH_WTMP
151#ifdef   WTMPX_FILE
152#define _PATH_WTMP   WTMPX_FILE
153#else
154#error  You must define WTMPX_FILE in the file config.h
155#endif
156#endif
157
158#else
159
160#ifndef _PATH_UTMP
161#ifdef   UTMP_FILE
162#define _PATH_UTMP   UTMP_FILE
163#else 
164#error  You must define UTMP_FILE in the file config.h
165#endif
166#endif
167#ifndef _PATH_WTMP
168#ifdef   WTMP_FILE
169#define _PATH_WTMP   WTMP_FILE
170#else
171#error  You must define WTMP_FILE in the file config.h
172#endif
173#endif
174
175#endif
176
177typedef struct log_user {
178  char                ut_tty[UT_LINESIZE+1];   
179  char                name[UT_NAMESIZE+1];
180  char                ut_host[UT_HOSTSIZE+1];
181  char                ut_ship[SH_IP_BUF]; /* IP address */
182  time_t              time;
183  struct log_user   * next;
184} blah_utmp;
185
186#ifdef HAVE_UTTYPE
187static char   terminated_line[UT_HOSTSIZE]; 
188#endif
189
190static char * mode_path[] = { _PATH_WTMP, _PATH_WTMP, _PATH_UTMP };
191
192static struct SH_UTMP_S save_utmp;
193
194static void sh_utmp_logout_morechecks(struct log_user   * user);
195static void sh_utmp_login_morechecks(struct SH_UTMP_S * ut);
196static void sh_utmp_addlogin (struct SH_UTMP_S * ut);
197static void sh_utmp_check_internal(int mode);
198
199static int    ShUtmpLoginSolo    = SH_ERR_INFO;
200static int    ShUtmpLoginMulti   = SH_ERR_WARN;
201static int    ShUtmpLogout       = SH_ERR_INFO;
202static int    ShUtmpActive       = S_TRUE;
203static time_t ShUtmpInterval     = 300;
204
205sh_rconf sh_utmp_table[] = {
206  {
207    N_("severityloginmulti"),
208    sh_utmp_set_login_multi
209  },
210  {
211    N_("severitylogin"),
212    sh_utmp_set_login_solo
213  },
214  {
215    N_("severitylogout"),
216    sh_utmp_set_logout_good
217  },
218  {
219    N_("logincheckactive"),
220    sh_utmp_set_login_activate
221  },
222  {
223    N_("logincheckinterval"),
224    sh_utmp_set_login_timer
225  },
226  {
227    N_("logincheckfirst"),
228    sh_login_set_checklevel
229  },
230  {
231    N_("logincheckoutlier"),
232    sh_login_set_siglevel
233  },
234  {
235    N_("logincheckdate"),
236    sh_login_set_def_allow
237  },
238  {
239    N_("logincheckuserdate"),
240    sh_login_set_user_allow
241  },
242  {
243    NULL,
244    NULL
245  },
246};
247
248static void set_defaults(void)
249{
250  ShUtmpLoginSolo    = SH_ERR_INFO;
251  ShUtmpLoginMulti   = SH_ERR_WARN;
252  ShUtmpLogout       = SH_ERR_INFO;
253  ShUtmpActive       = S_TRUE;
254  ShUtmpInterval     = 300;
255
256  sh_login_reset();
257  return;
258}
259
260
261#if defined (HAVE_SETUTENT) && defined (USE_SETUTENT)
262
263#ifdef HAVE_UTMPX_H
264
265#define sh_utmp_utmpname     utmpxname
266#define sh_utmp_setutent     setutxent
267#define sh_utmp_endutent     endutxent
268#define sh_utmp_getutent     getutxent
269#define sh_utmp_getutid      getutxid
270#define sh_utmp_getutline    getutxline
271
272#else
273
274#define sh_utmp_utmpname     utmpname
275#define sh_utmp_setutent     setutent
276#define sh_utmp_endutent     endutent
277#define sh_utmp_getutent     getutent
278#define sh_utmp_getutid      getutid
279#define sh_utmp_getutline    getutline
280
281#endif
282
283#else
284
285/* BSD lacks getutent() etc.
286 * utmpname(), setutent(), and endutent() return void,
287 * so we do not perform much error handling.
288 * Errors must be recognized by getutent() returning NULL.
289 * Apparently, the application cannot check whether wtmp is empty,
290 * or whether there was an fopen() error.
291 */
292
293static FILE * sh_utmpfile = NULL;
294static char   sh_utmppath[80] = _PATH_UTMP;
295
296/* sh_utmp_feed_forward is for optimizing
297 * (fseek instead of getutent loop)
298 */
299static long   sh_utmp_feed_forward = 0;
300
301static void sh_utmp_utmpname(const char * str)
302{
303  SL_ENTER(_("sh_utmp_utmpname"));
304  if (sh_utmpfile != NULL)
305    {
306      (void) sl_fclose (FIL__, __LINE__, sh_utmpfile);
307      sh_utmpfile = NULL;
308    }
309
310  (void) sl_strlcpy (sh_utmppath, str, 80);
311  SL_RET0(_("sh_utmp_utmpname"));
312}
313
314static void sh_utmp_setutent(void)
315{
316  int error;
317  int fd;
318
319  SL_ENTER(_("sh_utmp_setutent"));
320
321  if (sh_utmpfile == NULL) 
322    {
323      SH_MUTEX_LOCK(mutex_thread_nolog);
324      fd = (int) aud_open (FIL__, __LINE__, SL_NOPRIV, 
325                           sh_utmppath, O_RDONLY, 0);
326      SH_MUTEX_UNLOCK(mutex_thread_nolog);
327      if (fd >= 0)
328        {
329          sh_utmpfile = fdopen(fd, "r");
330        }
331
332      /* -- If (sh_utmpfile == NULL) then either the open() or the fdopen()
333       *    has failed.
334       */
335      if (sh_utmpfile == NULL) 
336        {
337          error = errno;
338          SH_MUTEX_LOCK(mutex_thread_nolog);
339          sh_error_handle ((-1), FIL__, __LINE__, error, MSG_E_ACCESS,
340                           (long) sh.real.uid, sh_utmppath);
341          SH_MUTEX_UNLOCK(mutex_thread_nolog);
342          SL_RET0(_("sh_utmp_setutent"));
343        }
344    }
345  (void) fseek (sh_utmpfile, 0L, SEEK_SET);
346  if (-1 == fseek (sh_utmpfile, sh_utmp_feed_forward, SEEK_CUR))
347    {
348      sh_utmp_feed_forward = 0; /* modified Apr 4, 2004 */
349      (void) fseek (sh_utmpfile, 0L, SEEK_SET);
350    }
351  clearerr (sh_utmpfile);
352  SL_RET0(_("sh_utmp_setutent"));
353}
354
355static void sh_utmp_endutent(void)
356{
357  SL_ENTER(_("sh_utmp_endutent"));
358  if (NULL != sh_utmpfile)
359    (void) sl_fclose(FIL__, __LINE__, sh_utmpfile);
360  sh_utmpfile = NULL;
361  SL_RET0(_("sh_utmp_endutent"));
362}
363
364static struct SH_UTMP_S * sh_utmp_getutent(void)
365{
366  size_t in;
367  static struct SH_UTMP_S out;
368
369  SL_ENTER(_("sh_utmp_getutent"));
370
371  ASSERT_RET((sh_utmpfile != NULL), _("sh_utmpfile != NULL"), (NULL))
372
373  in = fread (&out, sizeof(struct SH_UTMP_S), 1, sh_utmpfile);
374
375  if (in != 1) 
376    {
377      if (ferror (sh_utmpfile) != 0) 
378        {
379          clearerr (sh_utmpfile);
380          SL_RETURN(NULL, _("sh_utmp_getutent"));
381        } 
382      else 
383        {
384          SL_RETURN(NULL, _("sh_utmp_getutent"));
385        }
386    }
387  SL_RETURN(&out, _("sh_utmp_getutent"));
388}
389
390#ifdef USE_UNUSED
391
392static struct SH_UTMP_S * sh_utmp_getutline(struct SH_UTMP_S * ut)
393{
394  struct SH_UTMP_S * out;
395 
396  while (1) {
397      if ((out = sh_utmp_getutent()) == NULL) {
398        return NULL;
399      }
400#ifdef HAVE_UTTYPE 
401      if (out->ut_type == USER_PROCESS || out->ut_type == LOGIN_PROCESS)
402        if (sl_strcmp(ut->ut_line, out->ut_line) == 0) 
403          return out;
404#else
405      if ( 0 != sl_strncmp (out->ut_name, "reboot",   6) &&
406           0 != sl_strncmp (out->ut_name, "shutdown", 8) &&
407           0 != sl_strncmp (out->ut_name, "date",     4) )
408        return out;
409#endif
410  }
411  return NULL;
412}
413
414static struct SH_UTMP_S * sh_utmp_getutid(struct SH_UTMP_S * ut)
415{
416#ifdef HAVE_UTTYPE 
417  struct SH_UTMP_S * out;
418
419  if (ut->ut_type == RUN_LVL  || ut->ut_type == BOOT_TIME ||
420      ut->ut_type == NEW_TIME || ut->ut_type == OLD_TIME) 
421    {
422      while (1) {
423        if ((out = sh_utmp_getutent()) == NULL) {
424          return NULL;
425        }
426        if (out->ut_type == ut->ut_type) 
427          return out;
428      }
429    } 
430  else if (ut->ut_type == INIT_PROCESS || ut->ut_type == LOGIN_PROCESS ||
431           ut->ut_type == USER_PROCESS || ut->ut_type == DEAD_PROCESS ) 
432    {
433      while (1) {
434        if ((out = sh_utmp_getutent()) == NULL) {
435          return NULL;
436        }
437        if (sl_strcmp(ut->ut_id, out->ut_id) == 0) 
438          return out;
439      }
440    }
441#endif
442  return NULL;
443}
444/* #ifdef USE_UNUSED */
445#endif
446
447/* #ifdef HAVE_SETUTENT */
448#endif
449
450#ifdef HAVE_UTADDR
451#ifdef HAVE_UTADDR_V6
452static char * my_inet_ntoa(SINT32 * ut_addr_v6, char * buf, size_t buflen)
453{
454  struct in_addr in;
455
456  buf[0] = '\0';
457
458  if (0 == (ut_addr_v6[1] + ut_addr_v6[2] + ut_addr_v6[3]))
459    {
460      memcpy(&in, ut_addr_v6, sizeof(struct in_addr));
461      sl_strlcpy(buf, inet_ntoa(in), buflen);
462    }
463  else
464    {
465      inet_ntop(AF_INET6, ut_addr_v6, buf, buflen);
466    }
467  return buf;
468}
469#else
470static char * my_inet_ntoa(SINT32 ut_addr, char * buf, size_t buflen)
471{
472  struct in_addr in;
473
474  buf[0] = '\0';
475
476  memcpy(&in, ut_addr, sizeof(struct in_addr));
477  sl_strlcpy(buf, inet_ntoa(in), buflen);
478  return buf;
479}
480#endif
481/* #ifdef HAVE_UTADDR */
482#endif
483
484#if defined(__linux__) && !defined(ut_addr)
485#define ut_addr         ut_addr_v6[0]
486#endif
487
488
489static struct log_user   * userlist   = NULL;
490static time_t  lastcheck;
491static int     init_done = 0;
492
493/*************
494 *
495 * module init
496 *
497 *************/
498
499static int sh_utmp_init_internal (void)
500{
501
502  SL_ENTER(_("sh_utmp_init"));
503  if (ShUtmpActive == BAD)
504    SL_RETURN( (-1), _("sh_utmp_init"));
505
506  /* do not re-initialize after a re-configuration
507   */
508  if (init_done == 1) {
509    SL_RETURN( (0), _("sh_utmp_init"));
510  }
511  lastcheck  = time (NULL);
512  userlist   = NULL;
513  memset (&save_utmp, 0, sizeof(struct SH_UTMP_S));
514  sh_utmp_check_internal (2); /* current logins */
515  sh_utmp_check_internal (0);
516  init_done = 1;
517  SL_RETURN( (0), _("sh_utmp_init"));
518}
519
520int sh_utmp_init (struct mod_type * arg)
521{
522#if !defined(HAVE_PTHREAD)
523  (void) arg;
524#endif
525  if (ShUtmpActive == BAD)
526    return SH_MOD_FAILED;
527#ifdef HAVE_PTHREAD
528  if (arg != NULL && arg->initval < 0 && 
529      (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
530    {
531      if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
532        return SH_MOD_THREAD;
533      else
534        return SH_MOD_FAILED;
535    }
536  else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
537           (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
538    {
539      return SH_MOD_THREAD;
540    }
541#endif
542  return sh_utmp_init_internal();
543}
544
545/*************
546 *
547 * module cleanup
548 *
549 *************/
550#ifdef HAVE_UTTYPE
551static int sh_utmp_login_clean(void);
552#endif
553
554#if defined(HAVE_PTHREAD)
555static sh_watches inotify_watch = SH_INOTIFY_INITIALIZER;
556#endif
557
558int sh_utmp_end ()
559{
560  struct log_user * user    = userlist;
561  struct log_user * userold;
562
563  SL_ENTER(_("sh_utmp_end"));
564  while (user)
565    {
566      userold = user;
567      user    = user->next;
568      SH_FREE(userold);
569    }
570  userlist = NULL;
571#ifdef HAVE_UTTYPE
572  (void) sh_utmp_login_clean();
573#endif
574  /* Reset the flag, such that the module
575   * can be re-enabled.
576   */
577  set_defaults();
578  init_done          = 0;
579
580#if defined(HAVE_PTHREAD)
581  sh_inotify_remove(&inotify_watch);
582#endif
583
584  SL_RETURN( (0), _("sh_utmp_end"));
585}
586
587
588int sh_utmp_reconf()
589{
590  set_defaults();
591#if defined(HAVE_PTHREAD)
592  sh_inotify_remove(&inotify_watch);
593#endif
594  return 0;
595}
596
597
598/*************
599 *
600 * module timer
601 *
602 *************/
603int sh_utmp_timer (time_t tcurrent)
604{
605#if !defined(HAVE_PTHREAD)
606  retry_msleep(1, 0);
607
608  if ((time_t) (tcurrent - lastcheck) >= ShUtmpInterval)
609    {
610      lastcheck  = tcurrent;
611      return (-1);
612    }
613  return 0;
614#else
615  int errnum = 0;
616 
617  if ( (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE) &&
618       sh.flag.checkSum != SH_CHECK_INIT )
619    {
620      sh_inotify_wait_for_change(mode_path[1], &inotify_watch, 
621                                 &errnum, ShUtmpInterval);
622    }
623 
624  lastcheck  = tcurrent;
625
626  if (SH_INOTIFY_ERROR(errnum))
627    {
628      char ebuf[SH_ERRBUF_SIZE];
629
630      SH_MUTEX_LOCK(mutex_thread_nolog);
631      sh_error_message(errnum, ebuf, sizeof(ebuf));
632      sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, errnum, MSG_E_SUBGEN,
633                       ebuf,
634                       _("sh_utmp_timer") );
635      SH_MUTEX_UNLOCK(mutex_thread_nolog);   
636    }
637  return -1;
638#endif
639}
640
641/*************
642 *
643 * module check
644 *
645 *************/
646int sh_utmp_check ()
647{
648  SL_ENTER(_("sh_utmp_check"));
649  if (ShUtmpActive == BAD)
650    {
651#if defined(HAVE_PTHREAD)
652      sh_inotify_remove(&inotify_watch);
653#endif
654      SL_RETURN( (-1), _("sh_utmp_check"));
655    }
656  SH_MUTEX_LOCK(mutex_thread_nolog);
657  sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_UT_CHECK);
658  SH_MUTEX_UNLOCK(mutex_thread_nolog);
659  sh_utmp_check_internal (1);
660
661  SL_RETURN(0, _("sh_utmp_check"));
662}
663
664/*************
665 *
666 * module setup
667 *
668 *************/
669
670int sh_utmp_set_login_solo  (const char * c)
671{
672  int retval;
673  char tmp[32];
674
675  SL_ENTER(_("sh_utmp_set_login_solo"));
676  tmp[0] = '='; tmp[1] = '\0';
677  (void) sl_strlcat (tmp, c, 32);
678  SH_MUTEX_LOCK(mutex_thread_nolog);
679  retval = sh_error_set_level (tmp, &ShUtmpLoginSolo);
680  SH_MUTEX_UNLOCK(mutex_thread_nolog);
681  SL_RETURN(retval, _("sh_utmp_set_login_solo"));
682}
683
684int sh_utmp_set_login_multi (const char * c)
685{
686  int retval;
687  char tmp[32];
688
689  SL_ENTER(_("sh_utmp_set_login_multi"));
690  tmp[0] = '='; tmp[1] = '\0';
691  (void) sl_strlcat (tmp, c, 32);
692  SH_MUTEX_LOCK(mutex_thread_nolog);
693  retval = sh_error_set_level (tmp, &ShUtmpLoginMulti);
694  SH_MUTEX_UNLOCK(mutex_thread_nolog);
695  SL_RETURN(retval, _("sh_utmp_set_login_multi"));
696}
697
698int sh_utmp_set_logout_good (const char * c)
699{
700  int retval;
701  char tmp[32];
702
703  SL_ENTER(_("sh_utmp_set_logout_good"));
704  tmp[0] = '='; tmp[1] = '\0';
705  (void) sl_strlcat (tmp, c, 32);
706  SH_MUTEX_LOCK(mutex_thread_nolog);
707  retval = sh_error_set_level (tmp, &ShUtmpLogout);
708  SH_MUTEX_UNLOCK(mutex_thread_nolog);
709  SL_RETURN(retval, _("sh_utmp_set_logout_good"));
710}
711
712int sh_utmp_set_login_timer (const char * c)
713{
714  long val;
715
716  SL_ENTER(_("sh_utmp_set_login_timer"));
717  val = strtol (c, (char **)NULL, 10);
718  if (val <= 0)
719    {
720      SH_MUTEX_LOCK(mutex_thread_nolog);
721      sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
722                       _("utmp timer"), c);
723      SH_MUTEX_UNLOCK(mutex_thread_nolog);
724      SL_RETURN((-1), _("sh_utmp_set_login_timer"));
725    }
726
727  ShUtmpInterval = (time_t) val;
728  SL_RETURN(0, _("sh_utmp_set_login_timer"));
729}
730
731int sh_utmp_set_login_activate (const char * c)
732{
733  int i;
734  SL_ENTER(_("sh_utmp_set_login_activate"));
735  i = sh_util_flagval(c, &ShUtmpActive);
736  SL_RETURN(i, _("sh_utmp_set_login_activate"));
737}
738
739#ifdef HAVE_UTTYPE
740struct login_ct {
741  char name[UT_NAMESIZE+1];
742  int  nlogin;
743  struct login_ct * next;
744};
745
746static struct login_ct * login_ct_list = NULL;
747
748static int sh_utmp_login_clean(void)
749{
750  struct login_ct * list = login_ct_list;
751  struct login_ct * old;
752
753  login_ct_list = NULL;
754
755  while (list)
756    {
757      old  = list;
758      list = list->next;
759      SH_FREE(old);
760    }
761  return 0;
762}
763
764/* add a username to the list of logged-in users
765 */
766static int sh_utmp_login_a(char * str)
767{
768  struct login_ct * list = login_ct_list;
769
770  while (list)
771    {
772      if (0 == sl_strcmp(list->name, str))
773        {
774          ++(list->nlogin);
775          return list->nlogin;
776        }
777      list = list->next;
778    }
779  list = SH_ALLOC(sizeof(struct login_ct));
780  (void) sl_strlcpy(list->name, str, UT_NAMESIZE+1);
781  list->nlogin  = 1;
782  list->next    = login_ct_list;
783  login_ct_list = list;
784  return 1;
785}
786
787static int sh_utmp_login_r(char * str)
788{
789  struct login_ct * list = login_ct_list;
790  struct login_ct * old  = login_ct_list;
791
792  while (list)
793    {
794      if (0 == sl_strcmp(list->name, str))
795        {
796          list->nlogin -= 1;
797          if (list->nlogin > 0)
798            {
799              return list->nlogin;
800            }
801          if (login_ct_list == list) /* modified Apr 4, 2004 */
802            {
803              login_ct_list = list->next;
804              SH_FREE(list);
805            }
806          else
807            {
808              old->next = list->next;
809              SH_FREE(list);
810            }
811          return 0;
812        }
813      old  = list;
814      list = list->next;
815    }
816  return 0;
817}
818
819#endif
820
821
822/* for each login:
823 *    - allocate a log record
824 *    - link device.ut_record -> log_record
825 *    - link user.ut_record   -> log_record
826 */
827
828#ifdef HAVE_UTTYPE 
829static int sh_utmp_is_virtual (char * in_utline, char * in_uthost)
830{
831
832  if (in_uthost != NULL   &&
833      in_utline != NULL   &&
834      in_uthost[0] == ':' && 
835      in_uthost[1] == '0' && 
836      0 == sl_strncmp(in_utline, _("pts/"), 4))
837    {
838      return 1;
839    }
840
841  return 0;
842}
843#endif
844
845/* These variables are not used anywhere. They only exist
846 * to assign &userold, &user to them, which keeps gcc from
847 * putting them into a register, and avoids the 'clobbered
848 * by longjmp' warning. And no, 'volatile' proved insufficient.
849 */
850void * sh_dummy_850_userold = NULL;
851void * sh_dummy_851_user    = NULL;
852
853
854static void sh_utmp_addlogin (struct SH_UTMP_S * ut)
855{
856  struct log_user   * user     = userlist;
857  struct log_user   * userold  = userlist;
858#ifdef HAVE_UTTYPE 
859  struct log_user   * username = userlist;
860#endif
861
862  char   ttt[TIM_MAX];
863#ifdef HAVE_UTTYPE
864  volatile int    status;
865#endif
866
867  SL_ENTER(_("sh_utmp_addlogin"));
868
869  if (ut->ut_line[0] == '\0')
870    SL_RET0(_("sh_utmp_addlogin"));
871
872  /* for some stupid reason, AIX repeats the wtmp entry for logouts
873   * with ssh
874   */
875  if (memcmp (&save_utmp, ut, sizeof(struct SH_UTMP_S)) == 0)
876    {
877      memset(&save_utmp, 0, sizeof(struct SH_UTMP_S));
878      SL_RET0(_("sh_utmp_addlogin"));
879    }
880  memcpy (&save_utmp, ut, sizeof(struct SH_UTMP_S));
881
882  /* Take the address to keep gcc from putting them into registers.
883   * Avoids the 'clobbered by longjmp' warning.
884   */
885  sh_dummy_850_userold = (void*) &userold;
886  sh_dummy_851_user    = (void*) &user;
887
888  /* ------- find user --------
889   */
890  while (user != NULL) 
891    {
892      if (0 == sl_strncmp((char*)(user->ut_tty), ut->ut_line, UT_LINESIZE) ) 
893        break;
894      userold = user;
895      user = user->next;
896    }
897
898#ifdef HAVE_UTTYPE 
899  while (username != NULL) 
900    {
901      if (0 == sl_strncmp(username->name, ut->ut_name, UT_NAMESIZE) ) 
902        break;
903      username = username->next;
904    }
905#endif
906 
907#ifdef HAVE_UTTYPE 
908  /* ---------- LOGIN -------------- */
909  if (ut->ut_type == USER_PROCESS) 
910    {
911      if (user == NULL)
912        {
913          user = SH_ALLOC(sizeof(struct log_user));
914          user->next       = userlist;
915          userlist         = (struct log_user *) user;
916        }
917      (void) sl_strlcpy((char*)(user->ut_tty),  ut->ut_line, UT_LINESIZE+1);
918      (void) sl_strlcpy((char*)(user->name),    ut->ut_name, UT_NAMESIZE+1);
919#ifdef HAVE_UTHOST
920      (void) sl_strlcpy((char*)(user->ut_host), ut->ut_host, UT_HOSTSIZE+1);
921#else
922      user->ut_host[0] = '\0';
923#endif
924#ifdef HAVE_UTADDR
925#ifdef HAVE_UTADDR_V6
926      my_inet_ntoa(ut->ut_addr_v6, user->ut_ship, SH_IP_BUF);
927#else
928      my_inet_ntoa(ut->ut_addr, user->ut_ship, SH_IP_BUF);
929#endif
930#endif
931      user->time = ut->ut_time;
932
933      if (username == NULL                              /* not yet logged in */
934          || 0 == sl_strncmp(ut->ut_line, _("ttyp"), 4) /* in virt. console  */
935          || 0 == sl_strncmp(ut->ut_line, _("ttyq"), 4) /* in virt. console  */
936          ) {
937        status = sh_utmp_login_a((char*)user->name);
938        SH_MUTEX_LOCK(mutex_thread_nolog);
939        (void) sh_unix_time (user->time, ttt, TIM_MAX);
940        sh_error_handle( ShUtmpLoginSolo, FIL__, __LINE__, 0,
941#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
942                         MSG_UT_LG1X,
943#elif defined(HAVE_UTHOST)
944                         MSG_UT_LG1A,
945#else
946                         MSG_UT_LG1B,
947#endif
948                         user->name,
949                         user->ut_tty,
950#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
951                         user->ut_host,
952                         user->ut_ship,
953#elif defined(HAVE_UTHOST)
954                         user->ut_host,
955#endif
956                         ttt,
957                         status
958                         );
959        SH_MUTEX_UNLOCK(mutex_thread_nolog);
960      } else
961        if (0 == sh_utmp_is_virtual(ut->ut_line, (char*)user->ut_host))
962          {       
963            status = sh_utmp_login_a((char*)user->name);
964            SH_MUTEX_LOCK(mutex_thread_nolog);
965            (void) sh_unix_time (user->time, ttt, TIM_MAX);
966            sh_error_handle( ShUtmpLoginMulti, FIL__, __LINE__, 0,
967#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
968                             MSG_UT_LG2X,
969#elif defined(HAVE_UTHOST)
970                             MSG_UT_LG2A,
971#else
972                             MSG_UT_LG2B,
973#endif
974                             user->name,
975                             user->ut_tty,
976#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
977                             user->ut_host,
978                             user->ut_ship,
979#elif defined(HAVE_UTHOST)
980                             user->ut_host,
981#endif
982                             ttt,
983                             status
984                             );
985            SH_MUTEX_UNLOCK(mutex_thread_nolog);
986          }
987     
988      sh_utmp_login_morechecks(ut);
989      goto out;
990    }
991
992
993  /* ---------  LOGOUT ---------------- */
994  else if (ut->ut_name[0] == '\0'
995           || ut->ut_type == DEAD_PROCESS  /* solaris does not clear ut_name */
996           )
997    {
998      if (user != NULL)
999        {
1000#if defined(__linux__)
1001          if (0 == sh_utmp_is_virtual(ut->ut_line, (char*)user->ut_host)) {
1002#endif
1003            status = sh_utmp_login_r((char*)user->name);
1004            SH_MUTEX_LOCK(mutex_thread_nolog);
1005            (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX);
1006            sh_error_handle( ShUtmpLogout, FIL__, __LINE__, 0,
1007#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
1008                             MSG_UT_LG3X,
1009#elif defined(HAVE_UTHOST)
1010                             MSG_UT_LG3A,
1011#else
1012                             MSG_UT_LG3B,
1013#endif
1014                             user->name,
1015                             user->ut_tty,
1016#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
1017                             user->ut_host,
1018                             user->ut_ship,
1019#elif defined(HAVE_UTHOST)
1020                             user->ut_host,
1021#endif
1022                             ttt,
1023                             status
1024                             );
1025            SH_MUTEX_UNLOCK(mutex_thread_nolog);
1026            userold->next = user->next;
1027            if (user == userlist)
1028              userlist = user->next;
1029            sh_utmp_logout_morechecks((struct log_user *)user);
1030            SH_FREE((struct log_user *)user);
1031            user = NULL;
1032#if defined(__linux__)
1033          }
1034#endif
1035        }
1036      else
1037        {
1038          (void) sl_strlcpy(terminated_line, ut->ut_line, UT_HOSTSIZE);
1039          SH_MUTEX_LOCK(mutex_thread_nolog);
1040          (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX);
1041          sh_error_handle( ShUtmpLogout, FIL__, __LINE__, 0,
1042                           MSG_UT_LG3C,
1043                           terminated_line,
1044                           ttt, 0
1045                           );
1046          SH_MUTEX_UNLOCK(mutex_thread_nolog);
1047        }
1048      goto out;
1049    }
1050
1051  /* default */
1052  goto out;
1053
1054  /* #ifdef HAVE_UTTYPE                   */
1055#else
1056
1057  if (user == NULL)   /* probably a login */
1058    {
1059      user = SH_ALLOC(sizeof(struct log_user));
1060      sl_strlcpy(user->ut_tty,  ut->ut_line, UT_LINESIZE+1);
1061      sl_strlcpy(user->name,    ut->ut_name, UT_NAMESIZE+1);
1062#ifdef HAVE_UTHOST
1063      sl_strlcpy(user->ut_host, ut->ut_host, UT_HOSTSIZE+1);
1064#endif
1065#ifdef HAVE_UTADDR
1066#ifdef HAVE_UTADDR_V6
1067      my_inet_ntoa(ut->ut_addr_v6, user->ut_ship, SH_IP_BUF);
1068#else
1069      my_inet_ntoa(ut->ut_addr, user->ut_ship, SH_IP_BUF);
1070#endif
1071#endif
1072      user->time       = ut->ut_time;
1073      user->next       = userlist;
1074      userlist         = user;
1075
1076      SH_MUTEX_LOCK(mutex_thread_nolog);
1077      (void) sh_unix_time (user->time, ttt, TIM_MAX);
1078      sh_error_handle( ShUtmpLoginSolo, FIL__, __LINE__, 0,
1079#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
1080                       MSG_UT_LG1X,
1081#elif defined(HAVE_UTHOST)
1082                       MSG_UT_LG1A,
1083#else
1084                       MSG_UT_LG1B,
1085#endif
1086                       user->name,
1087                       user->ut_tty,
1088#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
1089                       user->ut_host,
1090                       user->ut_ship,
1091#elif defined(HAVE_UTHOST)
1092                       user->ut_host,
1093#endif
1094                       ttt,
1095                       1
1096                       );
1097      SH_MUTEX_UNLOCK(mutex_thread_nolog);
1098      sh_utmp_login_morechecks(ut);
1099    }
1100  else  /* probably a logout */
1101    {
1102      SH_MUTEX_LOCK(mutex_thread_nolog);
1103      (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX);
1104      sh_error_handle( ShUtmpLogout, FIL__, __LINE__, 0,
1105#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
1106                       MSG_UT_LG2X,
1107#elif defined(HAVE_UTHOST)
1108                       MSG_UT_LG2A,
1109#else
1110                       MSG_UT_LG2B,
1111#endif
1112                       user->name,
1113                       user->ut_tty,
1114#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
1115                       user->ut_host,
1116                       user->ut_ship,
1117#elif defined(HAVE_UTHOST)
1118                       user->ut_host,
1119#endif
1120                       ttt,
1121                       1
1122                       );
1123      SH_MUTEX_UNLOCK(mutex_thread_nolog);
1124      sh_utmp_logout_morechecks(user);
1125      userold->next = user->next;
1126      if (user == userlist)       /* inserted Apr 4, 2004 */
1127        userlist = user->next;
1128      SH_FREE(user);
1129      user = NULL;
1130    }
1131
1132#endif
1133
1134 out:
1135  sh_dummy_851_user    = NULL;
1136  sh_dummy_850_userold = NULL;
1137
1138  SL_RET0(_("sh_utmp_addlogin"));
1139}
1140
1141static time_t        lastmod  = 0;
1142static off_t         lastsize = 0;
1143static unsigned long lastread = 0;
1144
1145static void sh_utmp_check_internal (int mode)
1146{
1147  struct stat   buf;
1148  int           error;
1149  struct SH_UTMP_S * ut;
1150  unsigned long this_read;
1151  int           val_retry;
1152
1153  SL_ENTER(_("sh_utmp_check_internal"));
1154
1155  /* error if no access
1156   */
1157  do {
1158    val_retry = /*@-unrecog@*/lstat ( mode_path[mode], &buf)/*@+unrecog@*/;
1159  } while (val_retry < 0 && errno == EINTR);
1160
1161  if (0 != val_retry) 
1162    {
1163      error = errno;
1164      SH_MUTEX_LOCK(mutex_thread_nolog);
1165      sh_error_handle((-1), FIL__, __LINE__, error, MSG_E_ACCESS,
1166                      (long) sh.real.uid, mode_path[mode]);
1167      SH_MUTEX_UNLOCK(mutex_thread_nolog);
1168      SL_RET0(_("sh_utmp_check_internal"));
1169    }
1170
1171  /* modification time
1172   */
1173  if (mode < 2)
1174    {
1175      if (/*@-usedef@*/buf.st_mtime <= lastmod/*@+usedef@*/)
1176        { 
1177          SL_RET0(_("sh_utmp_check_internal"));
1178        }
1179      else
1180        lastmod = buf.st_mtime;
1181    }
1182
1183  /* file size
1184   */
1185  if (/*@-usedef@*/buf.st_size < lastsize/*@+usedef@*/ && mode < 2) 
1186    { 
1187      SH_MUTEX_LOCK(mutex_thread_nolog);
1188      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_UT_ROT,
1189                      mode_path[mode]);
1190      SH_MUTEX_UNLOCK(mutex_thread_nolog);
1191      lastread = 0;
1192#ifndef USE_SETUTENT
1193      sh_utmp_feed_forward = 0L;
1194#endif
1195    }
1196
1197  if (mode < 2)
1198    lastsize = buf.st_size;
1199
1200  if (buf.st_size == 0) 
1201    SL_RET0(_("sh_utmp_check_internal"));
1202
1203  sh_utmp_utmpname(mode_path[mode]);
1204  sh_utmp_setutent();
1205
1206  /*
1207   * feed forward if initializing
1208   * we need to do this here
1209   */
1210  this_read = 0;
1211
1212  if (mode < 2)
1213    {
1214      while (this_read < lastread) {
1215        (void) sh_utmp_getutent();
1216        ++this_read;
1217      }
1218    }
1219
1220  /* start reading
1221   */
1222  this_read = 0;
1223  while (1 == 1) {
1224    ut = sh_utmp_getutent();
1225    if (ut == NULL) 
1226      break;
1227    /* modified: ut_user --> ut_name */
1228    if (mode == 1 || (mode == 2 && ut->ut_name[0] != '\0'
1229#ifdef HAVE_UTTYPE
1230                      && ut->ut_type != DEAD_PROCESS
1231#endif
1232                      ))
1233      sh_utmp_addlogin (ut);
1234    ++this_read;
1235  }
1236
1237  sh_utmp_endutent();
1238
1239  if (mode < 2)
1240    {
1241      lastread += this_read;
1242#ifndef USE_SETUTENT
1243      sh_utmp_feed_forward += (long) (this_read * sizeof(struct SH_UTMP_S));
1244      lastread = 0;
1245#endif
1246    }
1247
1248  SL_RET0(_("sh_utmp_check_internal"));
1249}
1250
1251extern void sh_ltrack_check(struct SH_UTMP_S * ut);
1252
1253static void sh_utmp_login_morechecks(struct SH_UTMP_S * ut)
1254{
1255  sh_ltrack_check(ut);
1256  return;
1257}
1258
1259static void sh_utmp_logout_morechecks(struct log_user * user)
1260{
1261  (void) user;
1262  return;
1263}
1264
1265#endif
1266
1267
1268/* #ifdef SH_USE_UTMP */
1269#endif
1270
1271
1272
Note: See TracBrowser for help on using the repository browser.