source: trunk/src/sh_utmp.c@ 468

Last change on this file since 468 was 383, checked in by katerina, 13 years ago

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

File size: 28.0 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];
[295]181 char ut_ship[SH_IP_BUF]; /* IP address */
[1]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 {
[279]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 {
[1]243 NULL,
244 NULL
245 },
246};
247
[149]248static void set_defaults(void)
[1]249{
[149]250 ShUtmpLoginSolo = SH_ERR_INFO;
251 ShUtmpLoginMulti = SH_ERR_WARN;
252 ShUtmpLogout = SH_ERR_INFO;
253 ShUtmpActive = S_TRUE;
254 ShUtmpInterval = 300;
[279]255
256 sh_login_reset();
[149]257 return;
[1]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 {
[252]306 (void) sl_fclose (FIL__, __LINE__, sh_utmpfile);
[1]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 {
[143]328 SH_MUTEX_LOCK(mutex_thread_nolog);
[1]329 fd = (int) aud_open (FIL__, __LINE__, SL_NOPRIV,
330 sh_utmppath, O_RDONLY, 0);
[143]331 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[1]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;
[143]343 SH_MUTEX_LOCK(mutex_thread_nolog);
[1]344 sh_error_handle ((-1), FIL__, __LINE__, error, MSG_E_ACCESS,
345 (long) sh.real.uid, sh_utmppath);
[143]346 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[1]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"));
[30]363 if (NULL != sh_utmpfile)
[252]364 (void) sl_fclose(FIL__, __LINE__, sh_utmpfile);
[1]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
[295]456#ifdef HAVE_UTADDR_V6
457static char * my_inet_ntoa(SINT32 * ut_addr_v6, char * buf, size_t buflen)
[1]458{
[295]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;
[1]473}
474#else
[295]475static char * my_inet_ntoa(SINT32 ut_addr, char * buf, size_t buflen)
[1]476{
[295]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;
[1]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;
[142]496static int init_done = 0;
[1]497
498/*************
499 *
500 * module init
501 *
502 *************/
[142]503
[170]504static int sh_utmp_init_internal (void)
[1]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 */
[142]513 if (init_done == 1) {
[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);
[142]521 init_done = 1;
[1]522 SL_RETURN( (0), _("sh_utmp_init"));
523}
524
[142]525int sh_utmp_init (struct mod_type * arg)
526{
[279]527#if !defined(HAVE_PTHREAD)
528 (void) arg;
529#endif
[142]530 if (ShUtmpActive == BAD)
531 return SH_MOD_FAILED;
532#ifdef HAVE_PTHREAD
[144]533 if (arg != NULL && arg->initval < 0 &&
534 (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
[142]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 }
[332]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 }
[142]546#endif
547 return sh_utmp_init_internal();
548}
549
[1]550/*************
551 *
552 * module cleanup
553 *
554 *************/
555#ifdef HAVE_UTTYPE
[170]556static int sh_utmp_login_clean(void);
[1]557#endif
558
[259]559#if defined(HAVE_PTHREAD)
[363]560static sh_watches inotify_watch = SH_INOTIFY_INITIALIZER;
[259]561#endif
562
[1]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
[142]579 /* Reset the flag, such that the module
580 * can be re-enabled.
581 */
[149]582 set_defaults();
[142]583 init_done = 0;
[259]584
[279]585#if defined(HAVE_PTHREAD)
[259]586 sh_inotify_remove(&inotify_watch);
[279]587#endif
[259]588
[1]589 SL_RETURN( (0), _("sh_utmp_end"));
590}
591
[259]592
[149]593int sh_utmp_reconf()
594{
595 set_defaults();
[279]596#if defined(HAVE_PTHREAD)
[259]597 sh_inotify_remove(&inotify_watch);
[279]598#endif
[149]599 return 0;
600}
[1]601
[149]602
[1]603/*************
604 *
605 * module timer
606 *
607 *************/
608int sh_utmp_timer (time_t tcurrent)
609{
[259]610#if !defined(HAVE_PTHREAD)
611 retry_msleep(1, 0);
612
[1]613 if ((time_t) (tcurrent - lastcheck) >= ShUtmpInterval)
614 {
615 lastcheck = tcurrent;
616 return (-1);
617 }
618 return 0;
[259]619#else
620 int errnum = 0;
621
[262]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;
[259]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
[1]644}
645
646/*************
647 *
648 * module check
649 *
650 *************/
651int sh_utmp_check ()
652{
653 SL_ENTER(_("sh_utmp_check"));
[142]654 if (ShUtmpActive == BAD)
[259]655 {
656#if defined(HAVE_PTHREAD)
657 sh_inotify_remove(&inotify_watch);
658#endif
659 SL_RETURN( (-1), _("sh_utmp_check"));
660 }
[143]661 SH_MUTEX_LOCK(mutex_thread_nolog);
[1]662 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_UT_CHECK);
[143]663 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[1]664 sh_utmp_check_internal (1);
665
666 SL_RETURN(0, _("sh_utmp_check"));
667}
668
669/*************
670 *
671 * module setup
672 *
673 *************/
674
[68]675int sh_utmp_set_login_solo (const char * c)
[1]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);
[143]683 SH_MUTEX_LOCK(mutex_thread_nolog);
[1]684 retval = sh_error_set_level (tmp, &ShUtmpLoginSolo);
[143]685 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[1]686 SL_RETURN(retval, _("sh_utmp_set_login_solo"));
687}
688
[68]689int sh_utmp_set_login_multi (const char * c)
[1]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);
[143]697 SH_MUTEX_LOCK(mutex_thread_nolog);
[1]698 retval = sh_error_set_level (tmp, &ShUtmpLoginMulti);
[143]699 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[1]700 SL_RETURN(retval, _("sh_utmp_set_login_multi"));
701}
702
[68]703int sh_utmp_set_logout_good (const char * c)
[1]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);
[143]711 SH_MUTEX_LOCK(mutex_thread_nolog);
[1]712 retval = sh_error_set_level (tmp, &ShUtmpLogout);
[143]713 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[1]714 SL_RETURN(retval, _("sh_utmp_set_logout_good"));
715}
716
[68]717int sh_utmp_set_login_timer (const char * c)
[1]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 {
[143]725 SH_MUTEX_LOCK(mutex_thread_nolog);
[1]726 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
727 _("utmp timer"), c);
[143]728 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[170]729 SL_RETURN((-1), _("sh_utmp_set_login_timer"));
[1]730 }
731
732 ShUtmpInterval = (time_t) val;
733 SL_RETURN(0, _("sh_utmp_set_login_timer"));
734}
735
[68]736int sh_utmp_set_login_activate (const char * c)
[1]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
[170]753static int sh_utmp_login_clean(void)
[1]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 */
[259]832
[1]833#ifdef HAVE_UTTYPE
834static int sh_utmp_is_virtual (char * in_utline, char * in_uthost)
835{
[259]836
837 if (in_uthost != NULL &&
838 in_utline != NULL &&
[1]839 in_uthost[0] == ':' &&
840 in_uthost[1] == '0' &&
[259]841 0 == sl_strncmp(in_utline, _("pts/"), 4))
[1]842 {
[259]843 return 1;
[1]844 }
[259]845
846 return 0;
[1]847}
848#endif
849
[154]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 */
[170]855static void * sh_dummy_userold = NULL;
856static void * sh_dummy_user = NULL;
[154]857
858
[1]859static void sh_utmp_addlogin (struct SH_UTMP_S * ut)
860{
[154]861 struct log_user * user = userlist;
862 struct log_user * userold = userlist;
[1]863#ifdef HAVE_UTTYPE
864 struct log_user * username = userlist;
865#endif
866
867 char ttt[TIM_MAX];
868#ifdef HAVE_UTTYPE
[153]869 volatile int status;
[1]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
[383]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;
[1]892
893 /* ------- find user --------
894 */
895 while (user != NULL)
896 {
[154]897 if (0 == sl_strncmp((char*)(user->ut_tty), ut->ut_line, UT_LINESIZE) )
[1]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;
[154]920 userlist = (struct log_user *) user;
[1]921 }
[154]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);
[1]924#ifdef HAVE_UTHOST
[154]925 (void) sl_strlcpy((char*)(user->ut_host), ut->ut_host, UT_HOSTSIZE+1);
[1]926#else
927 user->ut_host[0] = '\0';
928#endif
929#ifdef HAVE_UTADDR
[295]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);
[1]934#endif
[295]935#endif
[1]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 ) {
[154]942 status = sh_utmp_login_a((char*)user->name);
[143]943 SH_MUTEX_LOCK(mutex_thread_nolog);
[132]944 (void) sh_unix_time (user->time, ttt, TIM_MAX);
[1]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 );
[143]964 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[1]965 } else
[259]966 if (0 == sh_utmp_is_virtual(ut->ut_line, (char*)user->ut_host))
[1]967 {
[154]968 status = sh_utmp_login_a((char*)user->name);
[143]969 SH_MUTEX_LOCK(mutex_thread_nolog);
[132]970 (void) sh_unix_time (user->time, ttt, TIM_MAX);
[1]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 );
[143]990 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[1]991 }
992
993 sh_utmp_login_morechecks(ut);
[383]994 goto out;
[1]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 {
[259]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,
[1]1012#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
[259]1013 MSG_UT_LG3X,
[1]1014#elif defined(HAVE_UTHOST)
[259]1015 MSG_UT_LG3A,
[1]1016#else
[259]1017 MSG_UT_LG3B,
[1]1018#endif
[259]1019 user->name,
1020 user->ut_tty,
[1]1021#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
[259]1022 user->ut_host,
1023 user->ut_ship,
[1]1024#elif defined(HAVE_UTHOST)
[259]1025 user->ut_host,
[1]1026#endif
[259]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
[1]1040 }
1041 else
1042 {
1043 (void) sl_strlcpy(terminated_line, ut->ut_line, UT_HOSTSIZE);
[143]1044 SH_MUTEX_LOCK(mutex_thread_nolog);
[132]1045 (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX);
[1]1046 sh_error_handle( ShUtmpLogout, FIL__, __LINE__, 0,
1047 MSG_UT_LG3C,
1048 terminated_line,
1049 ttt, 0
1050 );
[143]1051 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[1]1052 }
[383]1053 goto out;
[1]1054 }
1055
1056 /* default */
[383]1057 goto out;
[1]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
[295]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);
[1]1075#endif
[295]1076#endif
[1]1077 user->time = ut->ut_time;
1078 user->next = userlist;
1079 userlist = user;
1080
[143]1081 SH_MUTEX_LOCK(mutex_thread_nolog);
[132]1082 (void) sh_unix_time (user->time, ttt, TIM_MAX);
[1]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 );
[143]1102 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[1]1103 sh_utmp_login_morechecks(ut);
1104 }
1105 else /* probably a logout */
1106 {
[143]1107 SH_MUTEX_LOCK(mutex_thread_nolog);
[132]1108 (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX);
[1]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 );
[143]1128 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[1]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
[383]1137#endif
1138
1139 out:
1140 sh_dummy_user = NULL;
1141 sh_dummy_userold = NULL;
1142
[1]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;
[170]1155 unsigned long this_read;
[143]1156 int val_retry;
[1]1157
1158 SL_ENTER(_("sh_utmp_check_internal"));
1159
1160 /* error if no access
1161 */
[143]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)
[1]1167 {
1168 error = errno;
[143]1169 SH_MUTEX_LOCK(mutex_thread_nolog);
[1]1170 sh_error_handle((-1), FIL__, __LINE__, error, MSG_E_ACCESS,
1171 (long) sh.real.uid, mode_path[mode]);
[143]1172 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[1]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 {
[143]1192 SH_MUTEX_LOCK(mutex_thread_nolog);
[1]1193 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_UT_ROT,
1194 mode_path[mode]);
[143]1195 SH_MUTEX_UNLOCK(mutex_thread_nolog);
[1]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 */
[170]1215 this_read = 0;
1216
[1]1217 if (mode < 2)
1218 {
1219 while (this_read < lastread) {
[383]1220 (void) sh_utmp_getutent();
[1]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
[279]1256extern void sh_ltrack_check(struct SH_UTMP_S * ut);
[1]1257
1258static void sh_utmp_login_morechecks(struct SH_UTMP_S * ut)
1259{
[279]1260 sh_ltrack_check(ut);
[1]1261 return;
1262}
1263
1264static void sh_utmp_logout_morechecks(struct log_user * user)
1265{
[279]1266 (void) user;
[1]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.