source: trunk/src/sh_utmp.c@ 581

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

Fix for ticket #461 (login/logout monitoring on MacOS).

File size: 23.6 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#if defined(_PATH_UTMPX)
144#define SH_PATH_UTMP _PATH_UTMPX
145#elif defined(UTMPX_FILE)
146#define SH_PATH_UTMP UTMPX_FILE
147#elif defined(_PATH_UTMP)
148#define SH_PATH_UTMP _PATH_UTMP
149#else
150#error You must define UTMPX_FILE in the file config.h
151#endif
152
153#else
154
155#if defined(_PATH_UTMP)
156#define SH_PATH_UTMP _PATH_UTMP
157#elif defined(UTMP_FILE)
158#define SH_PATH_UTMP UTMP_FILE
159#else
160#error You must define UTMP_FILE in the file config.h
161#endif
162
163#endif
164
165typedef struct log_user {
166 time_t last_checked;
167 char ut_tty[UT_LINESIZE+1];
168 char name[UT_NAMESIZE+1];
169 char ut_host[UT_HOSTSIZE+1];
170 char ut_ship[SH_IP_BUF]; /* IP address */
171 time_t time;
172 struct log_user * next;
173} blah_utmp;
174
175static char * utmp_path = SH_PATH_UTMP;
176
177static void sh_utmp_logout_morechecks(struct log_user * user);
178static void sh_utmp_login_morechecks(struct SH_UTMP_S * ut);
179static void sh_utmp_checklogin (struct SH_UTMP_S * ut, time_t start_read);
180static void sh_utmp_check_internal();
181
182static int ShUtmpLoginSolo = SH_ERR_INFO;
183static int ShUtmpLoginMulti = SH_ERR_WARN;
184static int ShUtmpLogout = SH_ERR_INFO;
185static int ShUtmpActive = S_TRUE;
186static time_t ShUtmpInterval = 300;
187
188sh_rconf sh_utmp_table[] = {
189 {
190 N_("severityloginmulti"),
191 sh_utmp_set_login_multi
192 },
193 {
194 N_("severitylogin"),
195 sh_utmp_set_login_solo
196 },
197 {
198 N_("severitylogout"),
199 sh_utmp_set_logout_good
200 },
201 {
202 N_("logincheckactive"),
203 sh_utmp_set_login_activate
204 },
205 {
206 N_("logincheckinterval"),
207 sh_utmp_set_login_timer
208 },
209 {
210 N_("logincheckfirst"),
211 sh_login_set_checklevel
212 },
213 {
214 N_("logincheckoutlier"),
215 sh_login_set_siglevel
216 },
217 {
218 N_("logincheckdate"),
219 sh_login_set_def_allow
220 },
221 {
222 N_("logincheckuserdate"),
223 sh_login_set_user_allow
224 },
225 {
226 NULL,
227 NULL
228 },
229};
230
231static void set_defaults(void)
232{
233 ShUtmpLoginSolo = SH_ERR_INFO;
234 ShUtmpLoginMulti = SH_ERR_WARN;
235 ShUtmpLogout = SH_ERR_INFO;
236 ShUtmpActive = S_TRUE;
237 ShUtmpInterval = 300;
238
239 sh_login_reset();
240 return;
241}
242
243#if defined(HAVE_UTMPX_H) && defined(HAVE_GETUTXENT)
244#define USE_SETUTENT 1
245#elif defined(HAVE_GETUTENT)
246#define USE_SETUTENT 1
247#endif
248
249
250#if defined (USE_SETUTENT)
251
252#ifdef HAVE_UTMPX_H
253
254#define sh_utmp_utmpname(a) (void)(a)
255#define sh_utmp_setutent setutxent
256#define sh_utmp_endutent endutxent
257#define sh_utmp_getutent getutxent
258#define sh_utmp_getutid getutxid
259#define sh_utmp_getutline getutxline
260
261#else
262
263#define sh_utmp_utmpname utmpname
264#define sh_utmp_setutent setutent
265#define sh_utmp_endutent endutent
266#define sh_utmp_getutent getutent
267#define sh_utmp_getutid getutid
268#define sh_utmp_getutline getutline
269
270#endif
271
272#else
273
274/* BSD lacks getutent() etc.
275 * utmpname(), setutent(), and endutent() return void,
276 * so we do not perform much error handling.
277 * Errors must be recognized by getutent() returning NULL.
278 * Apparently, the application cannot check whether wtmp is empty,
279 * or whether there was an fopen() error.
280 */
281
282static FILE * sh_utmpfile = NULL;
283static char sh_utmppath[80] = SH_PATH_UTMP;
284
285
286static void sh_utmp_utmpname(const char * str)
287{
288 SL_ENTER(_("sh_utmp_utmpname"));
289 if (sh_utmpfile != NULL)
290 {
291 (void) sl_fclose (FIL__, __LINE__, sh_utmpfile);
292 sh_utmpfile = NULL;
293 }
294
295 (void) sl_strlcpy (sh_utmppath, str, sizeof(sh_utmppath));
296 SL_RET0(_("sh_utmp_utmpname"));
297}
298
299static void sh_utmp_setutent(void)
300{
301 int error;
302 int fd;
303
304 SL_ENTER(_("sh_utmp_setutent"));
305
306 if (sh_utmpfile == NULL)
307 {
308 SH_MUTEX_LOCK(mutex_thread_nolog);
309 fd = (int) aud_open (FIL__, __LINE__, SL_NOPRIV,
310 sh_utmppath, O_RDONLY, 0);
311 SH_MUTEX_UNLOCK(mutex_thread_nolog);
312 if (fd >= 0)
313 {
314 sh_utmpfile = fdopen(fd, "r");
315 }
316
317 /* -- If (sh_utmpfile == NULL) then either the open() or the fdopen()
318 * has failed.
319 */
320 if (sh_utmpfile == NULL)
321 {
322 error = errno;
323 SH_MUTEX_LOCK(mutex_thread_nolog);
324 sh_error_handle ((-1), FIL__, __LINE__, error, MSG_E_ACCESS,
325 (long) sh.real.uid, sh_utmppath);
326 SH_MUTEX_UNLOCK(mutex_thread_nolog);
327 SL_RET0(_("sh_utmp_setutent"));
328 }
329 }
330 (void) fseek (sh_utmpfile, 0L, SEEK_SET);
331 clearerr (sh_utmpfile);
332 SL_RET0(_("sh_utmp_setutent"));
333}
334
335static void sh_utmp_endutent(void)
336{
337 SL_ENTER(_("sh_utmp_endutent"));
338 if (NULL != sh_utmpfile)
339 (void) sl_fclose(FIL__, __LINE__, sh_utmpfile);
340 sh_utmpfile = NULL;
341 SL_RET0(_("sh_utmp_endutent"));
342}
343
344static struct SH_UTMP_S * sh_utmp_getutent(void)
345{
346 size_t in;
347 static struct SH_UTMP_S out;
348
349 SL_ENTER(_("sh_utmp_getutent"));
350
351 ASSERT_RET((sh_utmpfile != NULL), _("sh_utmpfile != NULL"), (NULL))
352
353 in = fread (&out, sizeof(struct SH_UTMP_S), 1, sh_utmpfile);
354
355 if (in != 1)
356 {
357 if (ferror (sh_utmpfile) != 0)
358 {
359 clearerr (sh_utmpfile);
360 SL_RETURN(NULL, _("sh_utmp_getutent"));
361 }
362 else
363 {
364 SL_RETURN(NULL, _("sh_utmp_getutent"));
365 }
366 }
367 SL_RETURN(&out, _("sh_utmp_getutent"));
368}
369
370/* #ifdef HAVE_SETUTENT */
371#endif
372
373#ifdef HAVE_UTADDR
374#ifdef HAVE_UTADDR_V6
375static char * my_inet_ntoa(SINT32 * ut_addr_v6, char * buf, size_t buflen)
376{
377 struct in_addr in;
378
379 buf[0] = '\0';
380
381 if (0 == (ut_addr_v6[1] + ut_addr_v6[2] + ut_addr_v6[3]))
382 {
383 memcpy(&in, ut_addr_v6, sizeof(struct in_addr));
384 sl_strlcpy(buf, inet_ntoa(in), buflen);
385 }
386 else
387 {
388 inet_ntop(AF_INET6, ut_addr_v6, buf, buflen);
389 }
390 return buf;
391}
392#else
393static char * my_inet_ntoa(SINT32 ut_addr, char * buf, size_t buflen)
394{
395 struct in_addr in;
396
397 buf[0] = '\0';
398
399 memcpy(&in, ut_addr, sizeof(struct in_addr));
400 sl_strlcpy(buf, inet_ntoa(in), buflen);
401 return buf;
402}
403#endif
404/* #ifdef HAVE_UTADDR */
405#endif
406
407#if defined(__linux__) && !defined(ut_addr)
408#define ut_addr ut_addr_v6[0]
409#endif
410
411
412static struct log_user * userlist = NULL;
413static time_t lastcheck;
414static int init_done = 0;
415
416/*************
417 *
418 * module init
419 *
420 *************/
421
422static int sh_utmp_init_internal (void)
423{
424
425 SL_ENTER(_("sh_utmp_init"));
426 if (ShUtmpActive == BAD)
427 SL_RETURN( (-1), _("sh_utmp_init"));
428
429 /* do not re-initialize after a re-configuration
430 */
431 if (init_done == 1) {
432 SL_RETURN( (0), _("sh_utmp_init"));
433 }
434 lastcheck = time (NULL);
435 userlist = NULL;
436 sh_utmp_check_internal (); /* current logins */
437 init_done = 1;
438 SL_RETURN( (0), _("sh_utmp_init"));
439}
440
441int sh_utmp_init (struct mod_type * arg)
442{
443#if !defined(HAVE_PTHREAD)
444 (void) arg;
445#endif
446 if (ShUtmpActive == BAD)
447 return SH_MOD_FAILED;
448#ifdef HAVE_PTHREAD
449 if (arg != NULL && arg->initval < 0 &&
450 (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
451 {
452 if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
453 return SH_MOD_THREAD;
454 else
455 return SH_MOD_FAILED;
456 }
457 else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
458 (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
459 {
460 return SH_MOD_THREAD;
461 }
462#endif
463 return sh_utmp_init_internal();
464}
465
466/*************
467 *
468 * module cleanup
469 *
470 *************/
471#ifdef HAVE_UTTYPE
472static int sh_utmp_login_clean(void);
473#endif
474
475#if defined(HAVE_PTHREAD)
476static sh_watches inotify_watch = SH_INOTIFY_INITIALIZER;
477#endif
478
479int sh_utmp_end ()
480{
481 struct log_user * user = userlist;
482 struct log_user * userold;
483
484 SL_ENTER(_("sh_utmp_end"));
485 while (user)
486 {
487 userold = user;
488 user = user->next;
489 SH_FREE(userold);
490 }
491 userlist = NULL;
492#ifdef HAVE_UTTYPE
493 (void) sh_utmp_login_clean();
494#endif
495 /* Reset the flag, such that the module
496 * can be re-enabled.
497 */
498 set_defaults();
499 init_done = 0;
500
501#if defined(HAVE_PTHREAD)
502 sh_inotify_remove(&inotify_watch);
503#endif
504
505 SL_RETURN( (0), _("sh_utmp_end"));
506}
507
508
509int sh_utmp_reconf()
510{
511 set_defaults();
512#if defined(HAVE_PTHREAD)
513 sh_inotify_remove(&inotify_watch);
514#endif
515 return 0;
516}
517
518
519/*************
520 *
521 * module timer
522 *
523 *************/
524int sh_utmp_timer (time_t tcurrent)
525{
526#if !defined(HAVE_PTHREAD)
527 retry_msleep(1, 0);
528
529 if ((time_t) (tcurrent - lastcheck) >= ShUtmpInterval)
530 {
531 lastcheck = tcurrent;
532 return (-1);
533 }
534 return 0;
535#else
536 int errnum = 0;
537
538 if ( (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE) &&
539 sh.flag.checkSum != SH_CHECK_INIT )
540 {
541 sh_inotify_wait_for_change(utmp_path, &inotify_watch,
542 &errnum, ShUtmpInterval);
543 }
544
545 lastcheck = tcurrent;
546
547 if (SH_INOTIFY_ERROR(errnum))
548 {
549 char ebuf[SH_ERRBUF_SIZE];
550
551 SH_MUTEX_LOCK(mutex_thread_nolog);
552 sh_error_message(errnum, ebuf, sizeof(ebuf));
553 sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, errnum, MSG_E_SUBGEN,
554 ebuf,
555 _("sh_utmp_timer") );
556 SH_MUTEX_UNLOCK(mutex_thread_nolog);
557 }
558 return -1;
559#endif
560}
561
562/*************
563 *
564 * module check
565 *
566 *************/
567int sh_utmp_check ()
568{
569 SL_ENTER(_("sh_utmp_check"));
570 if (ShUtmpActive == BAD)
571 {
572#if defined(HAVE_PTHREAD)
573 sh_inotify_remove(&inotify_watch);
574#endif
575 SL_RETURN( (-1), _("sh_utmp_check"));
576 }
577 SH_MUTEX_LOCK(mutex_thread_nolog);
578 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_UT_CHECK);
579 SH_MUTEX_UNLOCK(mutex_thread_nolog);
580 sh_utmp_check_internal ();
581
582 SL_RETURN(0, _("sh_utmp_check"));
583}
584
585/*************
586 *
587 * module setup
588 *
589 *************/
590
591int sh_utmp_set_login_solo (const char * c)
592{
593 int retval;
594 char tmp[32];
595
596 SL_ENTER(_("sh_utmp_set_login_solo"));
597 tmp[0] = '='; tmp[1] = '\0';
598 (void) sl_strlcat (tmp, c, 32);
599 SH_MUTEX_LOCK(mutex_thread_nolog);
600 retval = sh_error_set_level (tmp, &ShUtmpLoginSolo);
601 SH_MUTEX_UNLOCK(mutex_thread_nolog);
602 SL_RETURN(retval, _("sh_utmp_set_login_solo"));
603}
604
605int sh_utmp_set_login_multi (const char * c)
606{
607 int retval;
608 char tmp[32];
609
610 SL_ENTER(_("sh_utmp_set_login_multi"));
611 tmp[0] = '='; tmp[1] = '\0';
612 (void) sl_strlcat (tmp, c, 32);
613 SH_MUTEX_LOCK(mutex_thread_nolog);
614 retval = sh_error_set_level (tmp, &ShUtmpLoginMulti);
615 SH_MUTEX_UNLOCK(mutex_thread_nolog);
616 SL_RETURN(retval, _("sh_utmp_set_login_multi"));
617}
618
619int sh_utmp_set_logout_good (const char * c)
620{
621 int retval;
622 char tmp[32];
623
624 SL_ENTER(_("sh_utmp_set_logout_good"));
625 tmp[0] = '='; tmp[1] = '\0';
626 (void) sl_strlcat (tmp, c, 32);
627 SH_MUTEX_LOCK(mutex_thread_nolog);
628 retval = sh_error_set_level (tmp, &ShUtmpLogout);
629 SH_MUTEX_UNLOCK(mutex_thread_nolog);
630 SL_RETURN(retval, _("sh_utmp_set_logout_good"));
631}
632
633int sh_utmp_set_login_timer (const char * c)
634{
635 long val;
636
637 SL_ENTER(_("sh_utmp_set_login_timer"));
638 val = strtol (c, (char **)NULL, 10);
639 if (val <= 0)
640 {
641 SH_MUTEX_LOCK(mutex_thread_nolog);
642 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
643 _("utmp timer"), c);
644 SH_MUTEX_UNLOCK(mutex_thread_nolog);
645 SL_RETURN((-1), _("sh_utmp_set_login_timer"));
646 }
647
648 ShUtmpInterval = (time_t) val;
649 SL_RETURN(0, _("sh_utmp_set_login_timer"));
650}
651
652int sh_utmp_set_login_activate (const char * c)
653{
654 int i;
655 SL_ENTER(_("sh_utmp_set_login_activate"));
656 i = sh_util_flagval(c, &ShUtmpActive);
657 SL_RETURN(i, _("sh_utmp_set_login_activate"));
658}
659
660
661struct login_ct {
662 char name[UT_NAMESIZE+1];
663 int nlogin;
664 struct login_ct * next;
665};
666
667static struct login_ct * login_ct_list = NULL;
668
669static int sh_utmp_login_clean(void)
670{
671 struct login_ct * list = login_ct_list;
672 struct login_ct * old;
673
674 login_ct_list = NULL;
675
676 while (list)
677 {
678 old = list;
679 list = list->next;
680 SH_FREE(old);
681 }
682 return 0;
683}
684
685/* add a username to the list of logged-in users
686 */
687static int sh_utmp_login_a(char * str)
688{
689 struct login_ct * list = login_ct_list;
690
691 while (list)
692 {
693 if (0 == sl_strcmp(list->name, str))
694 {
695 ++(list->nlogin);
696 return list->nlogin;
697 }
698 list = list->next;
699 }
700 list = SH_ALLOC(sizeof(struct login_ct));
701 (void) sl_strlcpy(list->name, str, UT_NAMESIZE+1);
702 list->nlogin = 1;
703 list->next = login_ct_list;
704 login_ct_list = list;
705 return 1;
706}
707
708static int sh_utmp_login_r(char * str)
709{
710 struct login_ct * list = login_ct_list;
711 struct login_ct * old = login_ct_list;
712
713 while (list)
714 {
715 if (0 == sl_strcmp(list->name, str))
716 {
717 list->nlogin -= 1;
718 if (list->nlogin > 0)
719 {
720 return list->nlogin;
721 }
722 if (login_ct_list == list) /* modified Apr 4, 2004 */
723 {
724 login_ct_list = list->next;
725 SH_FREE(list);
726 }
727 else
728 {
729 old->next = list->next;
730 SH_FREE(list);
731 }
732 return 0;
733 }
734 old = list;
735 list = list->next;
736 }
737 return 0;
738}
739
740
741
742/* for each login:
743 * - allocate a log record
744 * - link device.ut_record -> log_record
745 * - link user.ut_record -> log_record
746 */
747
748#include <ctype.h>
749static int sh_utmp_is_virtual (char * in_utline, char * in_uthost)
750{
751
752 if (in_uthost != NULL &&
753 in_utline != NULL &&
754 in_uthost[0] == ':' &&
755 isdigit((int) in_uthost[1]) &&
756 0 == sl_strncmp(in_utline, _("pts/"), 4))
757 {
758 return 1;
759 }
760
761 return 0;
762}
763
764
765static void sh_utmp_log_out(int sev, struct log_user * user, int n)
766{
767 char ttt[TIM_MAX];
768
769 SH_MUTEX_LOCK(mutex_thread_nolog);
770 (void) sh_unix_time (user->time, ttt, TIM_MAX);
771 sh_error_handle( sev, FIL__, __LINE__, 0,
772#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
773 MSG_UT_LG3X,
774#elif defined(HAVE_UTHOST)
775 MSG_UT_LG3A,
776#else
777 MSG_UT_LG3B,
778#endif
779 user->name,
780 user->ut_tty,
781#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
782 user->ut_host,
783 user->ut_ship,
784#elif defined(HAVE_UTHOST)
785 user->ut_host,
786#endif
787 ttt,
788 n
789 );
790 SH_MUTEX_UNLOCK(mutex_thread_nolog);
791}
792
793static void sh_utmp_log_multi(int sev, struct log_user * user, int n)
794{
795 char ttt[TIM_MAX];
796
797 SH_MUTEX_LOCK(mutex_thread_nolog);
798 (void) sh_unix_time (user->time, ttt, TIM_MAX);
799 sh_error_handle( sev, FIL__, __LINE__, 0,
800#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
801 MSG_UT_LG2X,
802#elif defined(HAVE_UTHOST)
803 MSG_UT_LG2A,
804#else
805 MSG_UT_LG2B,
806#endif
807 user->name,
808 user->ut_tty,
809#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
810 user->ut_host,
811 user->ut_ship,
812#elif defined(HAVE_UTHOST)
813 user->ut_host,
814#endif
815 ttt,
816 n
817 );
818 SH_MUTEX_UNLOCK(mutex_thread_nolog);
819}
820
821static void sh_utmp_log_one(int sev, struct log_user * user, int n)
822{
823 char ttt[TIM_MAX];
824
825 SH_MUTEX_LOCK(mutex_thread_nolog);
826 (void) sh_unix_time (user->time, ttt, TIM_MAX);
827 sh_error_handle( sev, FIL__, __LINE__, 0,
828#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
829 MSG_UT_LG1X,
830#elif defined(HAVE_UTHOST)
831 MSG_UT_LG1A,
832#else
833 MSG_UT_LG1B,
834#endif
835 user->name,
836 user->ut_tty,
837#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
838 user->ut_host,
839 user->ut_ship,
840#elif defined(HAVE_UTHOST)
841 user->ut_host,
842#endif
843 ttt,
844 n
845 );
846 SH_MUTEX_UNLOCK(mutex_thread_nolog);
847}
848
849static void sh_utmp_purge_old (time_t start_read)
850{
851 struct log_user * user = userlist;
852 struct log_user * userold = userlist;
853 volatile int status;
854
855 /* ------- find old entries --------
856 */
857 while (user != NULL)
858 {
859 if (user->last_checked < start_read)
860 {
861 /* report logout */
862 if (0 == sh_utmp_is_virtual(user->ut_tty, user->ut_host))
863 {
864 /* reference count down on list of logged in users */
865 status = sh_utmp_login_r(user->name);
866
867 sh_utmp_log_out(ShUtmpLogout, user, status);
868 sh_utmp_logout_morechecks((struct log_user *)user);
869 }
870
871 /* remove entry */
872 if (userold == user && userold == userlist)
873 {
874 /* first element in userlist, advance userlist & userold */
875 userold = user->next;
876 userlist = user->next;
877 SH_FREE((struct log_user *)user);
878 user = userlist;
879 }
880 else
881 {
882 /* other element in userlist, cut it out */
883 userold->next = user->next;
884 SH_FREE((struct log_user *)user);
885 user = userold->next;
886 }
887 }
888 else
889 {
890 userold = user;
891 user = user->next;
892 }
893 }
894 return;
895}
896
897/* These variables are not used anywhere. They only exist
898 * to assign &userold, &user to them, which keeps gcc from
899 * putting them into a register, and avoids the 'clobbered
900 * by longjmp' warning. And no, 'volatile' proved insufficient.
901 */
902void * sh_dummy_850_userold = NULL;
903void * sh_dummy_851_user = NULL;
904
905
906static void sh_utmp_checklogin (struct SH_UTMP_S * ut, time_t start_read)
907{
908 struct log_user * user = userlist;
909 struct log_user * userold = userlist;
910
911 struct log_user * username = userlist;
912 volatile int status;
913
914
915 SL_ENTER(_("sh_utmp_checklogin"));
916
917 if (ut->ut_line[0] == '\0')
918 SL_RET0(_("sh_utmp_checklogin"));
919
920 /* Take the address to keep gcc from putting them into registers.
921 * Avoids the 'clobbered by longjmp' warning.
922 */
923 sh_dummy_850_userold = (void*) &userold;
924 sh_dummy_851_user = (void*) &user;
925
926 /* ------- find user --------
927 */
928 while (user != NULL)
929 {
930 if (0 == sl_strncmp(user->ut_tty, ut->ut_line, UT_LINESIZE) &&
931 0 == sl_strncmp(user->name, ut->ut_name, UT_NAMESIZE))
932 break;
933 userold = user;
934 user = user->next;
935 }
936
937
938 while (username != NULL)
939 {
940 if (0 == sl_strncmp(username->name, ut->ut_name, UT_NAMESIZE) )
941 break;
942 username = username->next;
943 }
944
945
946 if (user == NULL)
947 {
948 user = SH_ALLOC(sizeof(struct log_user));
949 user->next = userlist;
950 userlist = (struct log_user *) user;
951 }
952 else if ( (user->time == ut->ut_time) &&
953 0 == sl_strcmp (user->name, ut->ut_name))
954 {
955 /* we have it on record and nothing has changed */
956 user->last_checked = start_read;
957 goto out;
958 }
959 else
960 {
961 /* we have it on record and something has changed */
962 if (0 == sh_utmp_is_virtual(user->ut_tty, user->ut_host))
963 {
964 /* reference count down on list of logged in users */
965 status = sh_utmp_login_r(user->name);
966
967 sh_utmp_log_out(ShUtmpLogout, user, status);
968 sh_utmp_logout_morechecks((struct log_user *)user);
969 }
970 }
971
972 user->last_checked = start_read;
973
974 (void) sl_strlcpy(user->ut_tty, ut->ut_line, UT_LINESIZE+1);
975 (void) sl_strlcpy(user->name, ut->ut_name, UT_NAMESIZE+1);
976#ifdef HAVE_UTHOST
977 (void) sl_strlcpy(user->ut_host, ut->ut_host, UT_HOSTSIZE+1);
978#else
979 user->ut_host[0] = '\0';
980#endif
981#ifdef HAVE_UTADDR
982#ifdef HAVE_UTADDR_V6
983 my_inet_ntoa(ut->ut_addr_v6, user->ut_ship, SH_IP_BUF);
984#else
985 my_inet_ntoa(ut->ut_addr, user->ut_ship, SH_IP_BUF);
986#endif
987#endif
988 user->time = ut->ut_time;
989
990 if (username == NULL) /* not yet logged in */
991 {
992 /* add this username to the list of logged in users */
993 status = sh_utmp_login_a(user->name);
994
995 sh_utmp_log_one(ShUtmpLoginSolo, user, status);
996
997 }
998 else if (0 == sh_utmp_is_virtual(user->ut_tty, (char*)user->ut_host))
999 {
1000 /* add this username to the list of logged in users */
1001 status = sh_utmp_login_a((char*)user->name);
1002
1003 sh_utmp_log_multi(ShUtmpLoginMulti, user, status);
1004 }
1005 sh_utmp_login_morechecks(ut);
1006 goto out;
1007
1008
1009 out:
1010 sh_dummy_851_user = NULL;
1011 sh_dummy_850_userold = NULL;
1012
1013 SL_RET0(_("sh_utmp_checklogin"));
1014}
1015
1016static time_t lastmod = 0;
1017
1018static void sh_utmp_check_internal ()
1019{
1020 struct stat buf;
1021 int error;
1022 struct SH_UTMP_S * ut;
1023 int val_retry;
1024 time_t start_read;
1025
1026 SL_ENTER(_("sh_utmp_check_internal"));
1027
1028 /* error if no access
1029 */
1030 do {
1031 val_retry = /*@-unrecog@*/lstat ( utmp_path, &buf)/*@+unrecog@*/;
1032 } while (val_retry < 0 && errno == EINTR);
1033
1034 if (0 != val_retry)
1035 {
1036 error = errno;
1037 SH_MUTEX_LOCK(mutex_thread_nolog);
1038 sh_error_handle((-1), FIL__, __LINE__, error, MSG_E_ACCESS,
1039 (long) sh.real.uid, utmp_path);
1040 SH_MUTEX_UNLOCK(mutex_thread_nolog);
1041 SL_RET0(_("sh_utmp_check_internal"));
1042 }
1043
1044 /* check modification time
1045 */
1046 if (/*@-usedef@*/buf.st_mtime <= lastmod/*@+usedef@*/)
1047 {
1048 SL_RET0(_("sh_utmp_check_internal"));
1049 }
1050 else
1051 lastmod = buf.st_mtime;
1052
1053 sh_utmp_utmpname(utmp_path);
1054 sh_utmp_setutent();
1055
1056 /* start reading
1057 */
1058 start_read = time(NULL);
1059
1060 while (1 == 1) {
1061 ut = sh_utmp_getutent();
1062 if (ut == NULL)
1063 break;
1064 /* modified: ut_user --> ut_name */
1065 if (ut->ut_name[0] != '\0'
1066#ifdef HAVE_UTTYPE
1067 && ut->ut_type == USER_PROCESS
1068#endif
1069 )
1070 sh_utmp_checklogin (ut, start_read);
1071 }
1072
1073 sh_utmp_endutent();
1074
1075 sh_utmp_purge_old (start_read);
1076
1077 SL_RET0(_("sh_utmp_check_internal"));
1078}
1079
1080extern void sh_ltrack_check(struct SH_UTMP_S * ut);
1081
1082static void sh_utmp_login_morechecks(struct SH_UTMP_S * ut)
1083{
1084 sh_ltrack_check(ut);
1085 return;
1086}
1087
1088static void sh_utmp_logout_morechecks(struct log_user * user)
1089{
1090 (void) user;
1091 return;
1092}
1093
1094#endif
1095
1096
1097/* #ifdef SH_USE_UTMP */
1098#endif
1099
1100
1101
Note: See TracBrowser for help on using the repository browser.