source: trunk/src/sh_utmp.c @ 452

Last change on this file since 452 was 383, checked in by katerina, 10 years ago

Fix for ticket #281 (warnings from clang static analyzer).

File size: 28.0 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  ASSERT((sh_utmppath != NULL), _("sh_utmppath != NULL"));
322
323  if (sh_utmppath == NULL)
324    SL_RET0(_("sh_utmp_setutent"));
325
326  if (sh_utmpfile == NULL) 
327    {
328      SH_MUTEX_LOCK(mutex_thread_nolog);
329      fd = (int) aud_open (FIL__, __LINE__, SL_NOPRIV, 
330                           sh_utmppath, O_RDONLY, 0);
331      SH_MUTEX_UNLOCK(mutex_thread_nolog);
332      if (fd >= 0)
333        {
334          sh_utmpfile = fdopen(fd, "r");
335        }
336
337      /* -- If (sh_utmpfile == NULL) then either the open() or the fdopen()
338       *    has failed.
339       */
340      if (sh_utmpfile == NULL) 
341        {
342          error = errno;
343          SH_MUTEX_LOCK(mutex_thread_nolog);
344          sh_error_handle ((-1), FIL__, __LINE__, error, MSG_E_ACCESS,
345                           (long) sh.real.uid, sh_utmppath);
346          SH_MUTEX_UNLOCK(mutex_thread_nolog);
347          SL_RET0(_("sh_utmp_setutent"));
348        }
349    }
350  (void) fseek (sh_utmpfile, 0L, SEEK_SET);
351  if (-1 == fseek (sh_utmpfile, sh_utmp_feed_forward, SEEK_CUR))
352    {
353      sh_utmp_feed_forward = 0; /* modified Apr 4, 2004 */
354      (void) fseek (sh_utmpfile, 0L, SEEK_SET);
355    }
356  clearerr (sh_utmpfile);
357  SL_RET0(_("sh_utmp_setutent"));
358}
359
360static void sh_utmp_endutent(void)
361{
362  SL_ENTER(_("sh_utmp_endutent"));
363  if (NULL != sh_utmpfile)
364    (void) sl_fclose(FIL__, __LINE__, sh_utmpfile);
365  sh_utmpfile = NULL;
366  SL_RET0(_("sh_utmp_endutent"));
367}
368
369static struct SH_UTMP_S * sh_utmp_getutent(void)
370{
371  size_t in;
372  static struct SH_UTMP_S out;
373
374  SL_ENTER(_("sh_utmp_getutent"));
375
376  ASSERT_RET((sh_utmpfile != NULL), _("sh_utmpfile != NULL"), (NULL))
377
378  in = fread (&out, sizeof(struct SH_UTMP_S), 1, sh_utmpfile);
379
380  if (in != 1) 
381    {
382      if (ferror (sh_utmpfile) != 0) 
383        {
384          clearerr (sh_utmpfile);
385          SL_RETURN(NULL, _("sh_utmp_getutent"));
386        } 
387      else 
388        {
389          SL_RETURN(NULL, _("sh_utmp_getutent"));
390        }
391    }
392  SL_RETURN(&out, _("sh_utmp_getutent"));
393}
394
395#ifdef USE_UNUSED
396
397static struct SH_UTMP_S * sh_utmp_getutline(struct SH_UTMP_S * ut)
398{
399  struct SH_UTMP_S * out;
400 
401  while (1) {
402      if ((out = sh_utmp_getutent()) == NULL) {
403        return NULL;
404      }
405#ifdef HAVE_UTTYPE 
406      if (out->ut_type == USER_PROCESS || out->ut_type == LOGIN_PROCESS)
407        if (sl_strcmp(ut->ut_line, out->ut_line) == 0) 
408          return out;
409#else
410      if ( 0 != sl_strncmp (out->ut_name, "reboot",   6) &&
411           0 != sl_strncmp (out->ut_name, "shutdown", 8) &&
412           0 != sl_strncmp (out->ut_name, "date",     4) )
413        return out;
414#endif
415  }
416  return NULL;
417}
418
419static struct SH_UTMP_S * sh_utmp_getutid(struct SH_UTMP_S * ut)
420{
421#ifdef HAVE_UTTYPE 
422  struct SH_UTMP_S * out;
423
424  if (ut->ut_type == RUN_LVL  || ut->ut_type == BOOT_TIME ||
425      ut->ut_type == NEW_TIME || ut->ut_type == OLD_TIME) 
426    {
427      while (1) {
428        if ((out = sh_utmp_getutent()) == NULL) {
429          return NULL;
430        }
431        if (out->ut_type == ut->ut_type) 
432          return out;
433      }
434    } 
435  else if (ut->ut_type == INIT_PROCESS || ut->ut_type == LOGIN_PROCESS ||
436           ut->ut_type == USER_PROCESS || ut->ut_type == DEAD_PROCESS ) 
437    {
438      while (1) {
439        if ((out = sh_utmp_getutent()) == NULL) {
440          return NULL;
441        }
442        if (sl_strcmp(ut->ut_id, out->ut_id) == 0) 
443          return out;
444      }
445    }
446#endif
447  return NULL;
448}
449/* #ifdef USE_UNUSED */
450#endif
451
452/* #ifdef HAVE_SETUTENT */
453#endif
454
455#ifdef HAVE_UTADDR
456#ifdef HAVE_UTADDR_V6
457static char * my_inet_ntoa(SINT32 * ut_addr_v6, char * buf, size_t buflen)
458{
459  struct in_addr in;
460
461  buf[0] = '\0';
462
463  if (0 == (ut_addr_v6[1] + ut_addr_v6[2] + ut_addr_v6[3]))
464    {
465      memcpy(&in, ut_addr_v6, sizeof(struct in_addr));
466      sl_strlcpy(buf, inet_ntoa(in), buflen);
467    }
468  else
469    {
470      inet_ntop(AF_INET6, ut_addr_v6, buf, buflen);
471    }
472  return buf;
473}
474#else
475static char * my_inet_ntoa(SINT32 ut_addr, char * buf, size_t buflen)
476{
477  struct in_addr in;
478
479  buf[0] = '\0';
480
481  memcpy(&in, ut_addr, sizeof(struct in_addr));
482  sl_strlcpy(buf, inet_ntoa(in), buflen);
483  return buf;
484}
485#endif
486/* #ifdef HAVE_UTADDR */
487#endif
488
489#if defined(__linux__) && !defined(ut_addr)
490#define ut_addr         ut_addr_v6[0]
491#endif
492
493
494static struct log_user   * userlist   = NULL;
495static time_t  lastcheck;
496static int     init_done = 0;
497
498/*************
499 *
500 * module init
501 *
502 *************/
503
504static int sh_utmp_init_internal (void)
505{
506
507  SL_ENTER(_("sh_utmp_init"));
508  if (ShUtmpActive == BAD)
509    SL_RETURN( (-1), _("sh_utmp_init"));
510
511  /* do not re-initialize after a re-configuration
512   */
513  if (init_done == 1) {
514    SL_RETURN( (0), _("sh_utmp_init"));
515  }
516  lastcheck  = time (NULL);
517  userlist   = NULL;
518  memset (&save_utmp, 0, sizeof(struct SH_UTMP_S));
519  sh_utmp_check_internal (2); /* current logins */
520  sh_utmp_check_internal (0);
521  init_done = 1;
522  SL_RETURN( (0), _("sh_utmp_init"));
523}
524
525int sh_utmp_init (struct mod_type * arg)
526{
527#if !defined(HAVE_PTHREAD)
528  (void) arg;
529#endif
530  if (ShUtmpActive == BAD)
531    return SH_MOD_FAILED;
532#ifdef HAVE_PTHREAD
533  if (arg != NULL && arg->initval < 0 && 
534      (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
535    {
536      if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
537        return SH_MOD_THREAD;
538      else
539        return SH_MOD_FAILED;
540    }
541  else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
542           (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
543    {
544      return SH_MOD_THREAD;
545    }
546#endif
547  return sh_utmp_init_internal();
548}
549
550/*************
551 *
552 * module cleanup
553 *
554 *************/
555#ifdef HAVE_UTTYPE
556static int sh_utmp_login_clean(void);
557#endif
558
559#if defined(HAVE_PTHREAD)
560static sh_watches inotify_watch = SH_INOTIFY_INITIALIZER;
561#endif
562
563int sh_utmp_end ()
564{
565  struct log_user * user    = userlist;
566  struct log_user * userold;
567
568  SL_ENTER(_("sh_utmp_end"));
569  while (user)
570    {
571      userold = user;
572      user    = user->next;
573      SH_FREE(userold);
574    }
575  userlist = NULL;
576#ifdef HAVE_UTTYPE
577  (void) sh_utmp_login_clean();
578#endif
579  /* Reset the flag, such that the module
580   * can be re-enabled.
581   */
582  set_defaults();
583  init_done          = 0;
584
585#if defined(HAVE_PTHREAD)
586  sh_inotify_remove(&inotify_watch);
587#endif
588
589  SL_RETURN( (0), _("sh_utmp_end"));
590}
591
592
593int sh_utmp_reconf()
594{
595  set_defaults();
596#if defined(HAVE_PTHREAD)
597  sh_inotify_remove(&inotify_watch);
598#endif
599  return 0;
600}
601
602
603/*************
604 *
605 * module timer
606 *
607 *************/
608int sh_utmp_timer (time_t tcurrent)
609{
610#if !defined(HAVE_PTHREAD)
611  retry_msleep(1, 0);
612
613  if ((time_t) (tcurrent - lastcheck) >= ShUtmpInterval)
614    {
615      lastcheck  = tcurrent;
616      return (-1);
617    }
618  return 0;
619#else
620  int errnum = 0;
621 
622  if ( (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE) &&
623       sh.flag.checkSum != SH_CHECK_INIT )
624    {
625      sh_inotify_wait_for_change(mode_path[1], &inotify_watch, 
626                                 &errnum, ShUtmpInterval);
627    }
628 
629  lastcheck  = tcurrent;
630
631  if (SH_INOTIFY_ERROR(errnum))
632    {
633      char ebuf[SH_ERRBUF_SIZE];
634
635      SH_MUTEX_LOCK(mutex_thread_nolog);
636      sh_error_message(errnum, ebuf, sizeof(ebuf));
637      sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, errnum, MSG_E_SUBGEN,
638                       ebuf,
639                       _("sh_utmp_timer") );
640      SH_MUTEX_UNLOCK(mutex_thread_nolog);   
641    }
642  return -1;
643#endif
644}
645
646/*************
647 *
648 * module check
649 *
650 *************/
651int sh_utmp_check ()
652{
653  SL_ENTER(_("sh_utmp_check"));
654  if (ShUtmpActive == BAD)
655    {
656#if defined(HAVE_PTHREAD)
657      sh_inotify_remove(&inotify_watch);
658#endif
659      SL_RETURN( (-1), _("sh_utmp_check"));
660    }
661  SH_MUTEX_LOCK(mutex_thread_nolog);
662  sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_UT_CHECK);
663  SH_MUTEX_UNLOCK(mutex_thread_nolog);
664  sh_utmp_check_internal (1);
665
666  SL_RETURN(0, _("sh_utmp_check"));
667}
668
669/*************
670 *
671 * module setup
672 *
673 *************/
674
675int sh_utmp_set_login_solo  (const char * c)
676{
677  int retval;
678  char tmp[32];
679
680  SL_ENTER(_("sh_utmp_set_login_solo"));
681  tmp[0] = '='; tmp[1] = '\0';
682  (void) sl_strlcat (tmp, c, 32);
683  SH_MUTEX_LOCK(mutex_thread_nolog);
684  retval = sh_error_set_level (tmp, &ShUtmpLoginSolo);
685  SH_MUTEX_UNLOCK(mutex_thread_nolog);
686  SL_RETURN(retval, _("sh_utmp_set_login_solo"));
687}
688
689int sh_utmp_set_login_multi (const char * c)
690{
691  int retval;
692  char tmp[32];
693
694  SL_ENTER(_("sh_utmp_set_login_multi"));
695  tmp[0] = '='; tmp[1] = '\0';
696  (void) sl_strlcat (tmp, c, 32);
697  SH_MUTEX_LOCK(mutex_thread_nolog);
698  retval = sh_error_set_level (tmp, &ShUtmpLoginMulti);
699  SH_MUTEX_UNLOCK(mutex_thread_nolog);
700  SL_RETURN(retval, _("sh_utmp_set_login_multi"));
701}
702
703int sh_utmp_set_logout_good (const char * c)
704{
705  int retval;
706  char tmp[32];
707
708  SL_ENTER(_("sh_utmp_set_logout_good"));
709  tmp[0] = '='; tmp[1] = '\0';
710  (void) sl_strlcat (tmp, c, 32);
711  SH_MUTEX_LOCK(mutex_thread_nolog);
712  retval = sh_error_set_level (tmp, &ShUtmpLogout);
713  SH_MUTEX_UNLOCK(mutex_thread_nolog);
714  SL_RETURN(retval, _("sh_utmp_set_logout_good"));
715}
716
717int sh_utmp_set_login_timer (const char * c)
718{
719  long val;
720
721  SL_ENTER(_("sh_utmp_set_login_timer"));
722  val = strtol (c, (char **)NULL, 10);
723  if (val <= 0)
724    {
725      SH_MUTEX_LOCK(mutex_thread_nolog);
726      sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
727                       _("utmp timer"), c);
728      SH_MUTEX_UNLOCK(mutex_thread_nolog);
729      SL_RETURN((-1), _("sh_utmp_set_login_timer"));
730    }
731
732  ShUtmpInterval = (time_t) val;
733  SL_RETURN(0, _("sh_utmp_set_login_timer"));
734}
735
736int sh_utmp_set_login_activate (const char * c)
737{
738  int i;
739  SL_ENTER(_("sh_utmp_set_login_activate"));
740  i = sh_util_flagval(c, &ShUtmpActive);
741  SL_RETURN(i, _("sh_utmp_set_login_activate"));
742}
743
744#ifdef HAVE_UTTYPE
745struct login_ct {
746  char name[UT_NAMESIZE+1];
747  int  nlogin;
748  struct login_ct * next;
749};
750
751static struct login_ct * login_ct_list = NULL;
752
753static int sh_utmp_login_clean(void)
754{
755  struct login_ct * list = login_ct_list;
756  struct login_ct * old;
757
758  login_ct_list = NULL;
759
760  while (list)
761    {
762      old  = list;
763      list = list->next;
764      SH_FREE(old);
765    }
766  return 0;
767}
768
769/* add a username to the list of logged-in users
770 */
771static int sh_utmp_login_a(char * str)
772{
773  struct login_ct * list = login_ct_list;
774
775  while (list)
776    {
777      if (0 == sl_strcmp(list->name, str))
778        {
779          ++(list->nlogin);
780          return list->nlogin;
781        }
782      list = list->next;
783    }
784  list = SH_ALLOC(sizeof(struct login_ct));
785  (void) sl_strlcpy(list->name, str, UT_NAMESIZE+1);
786  list->nlogin  = 1;
787  list->next    = login_ct_list;
788  login_ct_list = list;
789  return 1;
790}
791
792static int sh_utmp_login_r(char * str)
793{
794  struct login_ct * list = login_ct_list;
795  struct login_ct * old  = login_ct_list;
796
797  while (list)
798    {
799      if (0 == sl_strcmp(list->name, str))
800        {
801          list->nlogin -= 1;
802          if (list->nlogin > 0)
803            {
804              return list->nlogin;
805            }
806          if (login_ct_list == list) /* modified Apr 4, 2004 */
807            {
808              login_ct_list = list->next;
809              SH_FREE(list);
810            }
811          else
812            {
813              old->next = list->next;
814              SH_FREE(list);
815            }
816          return 0;
817        }
818      old  = list;
819      list = list->next;
820    }
821  return 0;
822}
823
824#endif
825
826
827/* for each login:
828 *    - allocate a log record
829 *    - link device.ut_record -> log_record
830 *    - link user.ut_record   -> log_record
831 */
832
833#ifdef HAVE_UTTYPE 
834static int sh_utmp_is_virtual (char * in_utline, char * in_uthost)
835{
836
837  if (in_uthost != NULL   &&
838      in_utline != NULL   &&
839      in_uthost[0] == ':' && 
840      in_uthost[1] == '0' && 
841      0 == sl_strncmp(in_utline, _("pts/"), 4))
842    {
843      return 1;
844    }
845
846  return 0;
847}
848#endif
849
850/* These variables are not used anywhere. They only exist
851 * to assign &userold, &user to them, which keeps gcc from
852 * putting them into a register, and avoids the 'clobbered
853 * by longjmp' warning. And no, 'volatile' proved insufficient.
854 */
855static void * sh_dummy_userold = NULL;
856static void * sh_dummy_user    = NULL;
857
858
859static void sh_utmp_addlogin (struct SH_UTMP_S * ut)
860{
861  struct log_user   * user     = userlist;
862  struct log_user   * userold  = userlist;
863#ifdef HAVE_UTTYPE 
864  struct log_user   * username = userlist;
865#endif
866
867  char   ttt[TIM_MAX];
868#ifdef HAVE_UTTYPE
869  volatile int    status;
870#endif
871
872  SL_ENTER(_("sh_utmp_addlogin"));
873
874  if (ut->ut_line[0] == '\0')
875    SL_RET0(_("sh_utmp_addlogin"));
876
877  /* for some stupid reason, AIX repeats the wtmp entry for logouts
878   * with ssh
879   */
880  if (memcmp (&save_utmp, ut, sizeof(struct SH_UTMP_S)) == 0)
881    {
882      memset(&save_utmp, (int) '\0', sizeof(struct SH_UTMP_S));
883      SL_RET0(_("sh_utmp_addlogin"));
884    }
885  memcpy (&save_utmp, ut, sizeof(struct SH_UTMP_S));
886
887  /* Take the address to keep gcc from putting them into registers.
888   * Avoids the 'clobbered by longjmp' warning.
889   */
890  sh_dummy_userold = (void*) &userold;
891  sh_dummy_user    = (void*) &user;
892
893  /* ------- find user --------
894   */
895  while (user != NULL) 
896    {
897      if (0 == sl_strncmp((char*)(user->ut_tty), ut->ut_line, UT_LINESIZE) ) 
898        break;
899      userold = user;
900      user = user->next;
901    }
902
903#ifdef HAVE_UTTYPE 
904  while (username != NULL) 
905    {
906      if (0 == sl_strncmp(username->name, ut->ut_name, UT_NAMESIZE) ) 
907        break;
908      username = username->next;
909    }
910#endif
911 
912#ifdef HAVE_UTTYPE 
913  /* ---------- LOGIN -------------- */
914  if (ut->ut_type == USER_PROCESS) 
915    {
916      if (user == NULL)
917        {
918          user = SH_ALLOC(sizeof(struct log_user));
919          user->next       = userlist;
920          userlist         = (struct log_user *) user;
921        }
922      (void) sl_strlcpy((char*)(user->ut_tty),  ut->ut_line, UT_LINESIZE+1);
923      (void) sl_strlcpy((char*)(user->name),    ut->ut_name, UT_NAMESIZE+1);
924#ifdef HAVE_UTHOST
925      (void) sl_strlcpy((char*)(user->ut_host), ut->ut_host, UT_HOSTSIZE+1);
926#else
927      user->ut_host[0] = '\0';
928#endif
929#ifdef HAVE_UTADDR
930#ifdef HAVE_UTADDR_V6
931      my_inet_ntoa(ut->ut_addr_v6, user->ut_ship, SH_IP_BUF);
932#else
933      my_inet_ntoa(ut->ut_addr, user->ut_ship, SH_IP_BUF);
934#endif
935#endif
936      user->time = ut->ut_time;
937
938      if (username == NULL                              /* not yet logged in */
939          || 0 == sl_strncmp(ut->ut_line, _("ttyp"), 4) /* in virt. console  */
940          || 0 == sl_strncmp(ut->ut_line, _("ttyq"), 4) /* in virt. console  */
941          ) {
942        status = sh_utmp_login_a((char*)user->name);
943        SH_MUTEX_LOCK(mutex_thread_nolog);
944        (void) sh_unix_time (user->time, ttt, TIM_MAX);
945        sh_error_handle( ShUtmpLoginSolo, FIL__, __LINE__, 0,
946#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
947                         MSG_UT_LG1X,
948#elif defined(HAVE_UTHOST)
949                         MSG_UT_LG1A,
950#else
951                         MSG_UT_LG1B,
952#endif
953                         user->name,
954                         user->ut_tty,
955#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
956                         user->ut_host,
957                         user->ut_ship,
958#elif defined(HAVE_UTHOST)
959                         user->ut_host,
960#endif
961                         ttt,
962                         status
963                         );
964        SH_MUTEX_UNLOCK(mutex_thread_nolog);
965      } else
966        if (0 == sh_utmp_is_virtual(ut->ut_line, (char*)user->ut_host))
967          {       
968            status = sh_utmp_login_a((char*)user->name);
969            SH_MUTEX_LOCK(mutex_thread_nolog);
970            (void) sh_unix_time (user->time, ttt, TIM_MAX);
971            sh_error_handle( ShUtmpLoginMulti, FIL__, __LINE__, 0,
972#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
973                             MSG_UT_LG2X,
974#elif defined(HAVE_UTHOST)
975                             MSG_UT_LG2A,
976#else
977                             MSG_UT_LG2B,
978#endif
979                             user->name,
980                             user->ut_tty,
981#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
982                             user->ut_host,
983                             user->ut_ship,
984#elif defined(HAVE_UTHOST)
985                             user->ut_host,
986#endif
987                             ttt,
988                             status
989                             );
990            SH_MUTEX_UNLOCK(mutex_thread_nolog);
991          }
992     
993      sh_utmp_login_morechecks(ut);
994      goto out;
995    }
996
997
998  /* ---------  LOGOUT ---------------- */
999  else if (ut->ut_name[0] == '\0'
1000           || ut->ut_type == DEAD_PROCESS  /* solaris does not clear ut_name */
1001           )
1002    {
1003      if (user != NULL)
1004        {
1005#if defined(__linux__)
1006          if (0 == sh_utmp_is_virtual(ut->ut_line, (char*)user->ut_host)) {
1007#endif
1008            status = sh_utmp_login_r((char*)user->name);
1009            SH_MUTEX_LOCK(mutex_thread_nolog);
1010            (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX);
1011            sh_error_handle( ShUtmpLogout, FIL__, __LINE__, 0,
1012#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
1013                             MSG_UT_LG3X,
1014#elif defined(HAVE_UTHOST)
1015                             MSG_UT_LG3A,
1016#else
1017                             MSG_UT_LG3B,
1018#endif
1019                             user->name,
1020                             user->ut_tty,
1021#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
1022                             user->ut_host,
1023                             user->ut_ship,
1024#elif defined(HAVE_UTHOST)
1025                             user->ut_host,
1026#endif
1027                             ttt,
1028                             status
1029                             );
1030            SH_MUTEX_UNLOCK(mutex_thread_nolog);
1031            userold->next = user->next;
1032            if (user == userlist)
1033              userlist = user->next;
1034            sh_utmp_logout_morechecks((struct log_user *)user);
1035            SH_FREE((struct log_user *)user);
1036            user = NULL;
1037#if defined(__linux__)
1038          }
1039#endif
1040        }
1041      else
1042        {
1043          (void) sl_strlcpy(terminated_line, ut->ut_line, UT_HOSTSIZE);
1044          SH_MUTEX_LOCK(mutex_thread_nolog);
1045          (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX);
1046          sh_error_handle( ShUtmpLogout, FIL__, __LINE__, 0,
1047                           MSG_UT_LG3C,
1048                           terminated_line,
1049                           ttt, 0
1050                           );
1051          SH_MUTEX_UNLOCK(mutex_thread_nolog);
1052        }
1053      goto out;
1054    }
1055
1056  /* default */
1057  goto out;
1058
1059  /* #ifdef HAVE_UTTYPE                   */
1060#else
1061
1062  if (user == NULL)   /* probably a login */
1063    {
1064      user = SH_ALLOC(sizeof(struct log_user));
1065      sl_strlcpy(user->ut_tty,  ut->ut_line, UT_LINESIZE+1);
1066      sl_strlcpy(user->name,    ut->ut_name, UT_NAMESIZE+1);
1067#ifdef HAVE_UTHOST
1068      sl_strlcpy(user->ut_host, ut->ut_host, UT_HOSTSIZE+1);
1069#endif
1070#ifdef HAVE_UTADDR
1071#ifdef HAVE_UTADDR_V6
1072      my_inet_ntoa(ut->ut_addr_v6, user->ut_ship, SH_IP_BUF);
1073#else
1074      my_inet_ntoa(ut->ut_addr, user->ut_ship, SH_IP_BUF);
1075#endif
1076#endif
1077      user->time       = ut->ut_time;
1078      user->next       = userlist;
1079      userlist         = user;
1080
1081      SH_MUTEX_LOCK(mutex_thread_nolog);
1082      (void) sh_unix_time (user->time, ttt, TIM_MAX);
1083      sh_error_handle( ShUtmpLoginSolo, FIL__, __LINE__, 0,
1084#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
1085                       MSG_UT_LG1X,
1086#elif defined(HAVE_UTHOST)
1087                       MSG_UT_LG1A,
1088#else
1089                       MSG_UT_LG1B,
1090#endif
1091                       user->name,
1092                       user->ut_tty,
1093#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
1094                       user->ut_host,
1095                       user->ut_ship,
1096#elif defined(HAVE_UTHOST)
1097                       user->ut_host,
1098#endif
1099                       ttt,
1100                       1
1101                       );
1102      SH_MUTEX_UNLOCK(mutex_thread_nolog);
1103      sh_utmp_login_morechecks(ut);
1104    }
1105  else  /* probably a logout */
1106    {
1107      SH_MUTEX_LOCK(mutex_thread_nolog);
1108      (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX);
1109      sh_error_handle( ShUtmpLogout, FIL__, __LINE__, 0,
1110#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
1111                       MSG_UT_LG2X,
1112#elif defined(HAVE_UTHOST)
1113                       MSG_UT_LG2A,
1114#else
1115                       MSG_UT_LG2B,
1116#endif
1117                       user->name,
1118                       user->ut_tty,
1119#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
1120                       user->ut_host,
1121                       user->ut_ship,
1122#elif defined(HAVE_UTHOST)
1123                       user->ut_host,
1124#endif
1125                       ttt,
1126                       1
1127                       );
1128      SH_MUTEX_UNLOCK(mutex_thread_nolog);
1129      sh_utmp_logout_morechecks(user);
1130      userold->next = user->next;
1131      if (user == userlist)       /* inserted Apr 4, 2004 */
1132        userlist = user->next;
1133      SH_FREE(user);
1134      user = NULL;
1135    }
1136
1137#endif
1138
1139 out:
1140  sh_dummy_user    = NULL;
1141  sh_dummy_userold = NULL;
1142
1143  SL_RET0(_("sh_utmp_addlogin"));
1144}
1145
1146static time_t        lastmod  = 0;
1147static off_t         lastsize = 0;
1148static unsigned long lastread = 0;
1149
1150static void sh_utmp_check_internal (int mode)
1151{
1152  struct stat   buf;
1153  int           error;
1154  struct SH_UTMP_S * ut;
1155  unsigned long this_read;
1156  int           val_retry;
1157
1158  SL_ENTER(_("sh_utmp_check_internal"));
1159
1160  /* error if no access
1161   */
1162  do {
1163    val_retry = /*@-unrecog@*/lstat ( mode_path[mode], &buf)/*@+unrecog@*/;
1164  } while (val_retry < 0 && errno == EINTR);
1165
1166  if (0 != val_retry) 
1167    {
1168      error = errno;
1169      SH_MUTEX_LOCK(mutex_thread_nolog);
1170      sh_error_handle((-1), FIL__, __LINE__, error, MSG_E_ACCESS,
1171                      (long) sh.real.uid, mode_path[mode]);
1172      SH_MUTEX_UNLOCK(mutex_thread_nolog);
1173      SL_RET0(_("sh_utmp_check_internal"));
1174    }
1175
1176  /* modification time
1177   */
1178  if (mode < 2)
1179    {
1180      if (/*@-usedef@*/buf.st_mtime <= lastmod/*@+usedef@*/)
1181        { 
1182          SL_RET0(_("sh_utmp_check_internal"));
1183        }
1184      else
1185        lastmod = buf.st_mtime;
1186    }
1187
1188  /* file size
1189   */
1190  if (/*@-usedef@*/buf.st_size < lastsize/*@+usedef@*/ && mode < 2) 
1191    { 
1192      SH_MUTEX_LOCK(mutex_thread_nolog);
1193      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_UT_ROT,
1194                      mode_path[mode]);
1195      SH_MUTEX_UNLOCK(mutex_thread_nolog);
1196      lastread = 0;
1197#ifndef USE_SETUTENT
1198      sh_utmp_feed_forward = 0L;
1199#endif
1200    }
1201
1202  if (mode < 2)
1203    lastsize = buf.st_size;
1204
1205  if (buf.st_size == 0) 
1206    SL_RET0(_("sh_utmp_check_internal"));
1207
1208  sh_utmp_utmpname(mode_path[mode]);
1209  sh_utmp_setutent();
1210
1211  /*
1212   * feed forward if initializing
1213   * we need to do this here
1214   */
1215  this_read = 0;
1216
1217  if (mode < 2)
1218    {
1219      while (this_read < lastread) {
1220        (void) sh_utmp_getutent();
1221        ++this_read;
1222      }
1223    }
1224
1225  /* start reading
1226   */
1227  this_read = 0;
1228  while (1 == 1) {
1229    ut = sh_utmp_getutent();
1230    if (ut == NULL) 
1231      break;
1232    /* modified: ut_user --> ut_name */
1233    if (mode == 1 || (mode == 2 && ut->ut_name[0] != '\0'
1234#ifdef HAVE_UTTYPE
1235                      && ut->ut_type != DEAD_PROCESS
1236#endif
1237                      ))
1238      sh_utmp_addlogin (ut);
1239    ++this_read;
1240  }
1241
1242  sh_utmp_endutent();
1243
1244  if (mode < 2)
1245    {
1246      lastread += this_read;
1247#ifndef USE_SETUTENT
1248      sh_utmp_feed_forward += (long) (this_read * sizeof(struct SH_UTMP_S));
1249      lastread = 0;
1250#endif
1251    }
1252
1253  SL_RET0(_("sh_utmp_check_internal"));
1254}
1255
1256extern void sh_ltrack_check(struct SH_UTMP_S * ut);
1257
1258static void sh_utmp_login_morechecks(struct SH_UTMP_S * ut)
1259{
1260  sh_ltrack_check(ut);
1261  return;
1262}
1263
1264static void sh_utmp_logout_morechecks(struct log_user * user)
1265{
1266  (void) user;
1267  return;
1268}
1269
1270#endif
1271
1272
1273/* #ifdef SH_USE_UTMP */
1274#endif
1275
1276
1277
Note: See TracBrowser for help on using the repository browser.