source: trunk/src/sh_utmp.c@ 262

Last change on this file since 262 was 262, checked in by katerina, 15 years ago

Fix for ticket #179, and some minor bugfixes.

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