1 /* SAMHAIN file system integrity testing                                   */
2 /* Copyright (C) 2010 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 #undef  FIL__
23 #define FIL__  _("sh_login_track.c")
24 
25 #if defined(SH_USE_UTMP) && (defined(SH_WITH_CLIENT) || defined (SH_STANDALONE))
26 
27 #include <string.h>
28 
29 #include "samhain.h"
30 #include "sh_pthread.h"
31 #include "sh_utils.h"
32 #include "sh_unix.h"
33 #include "sh_string.h"
34 #include "sh_tools.h"
35 #include "sh_ipvx.h"
36 #include "sh_error_min.h"
37 
38 #ifdef HAVE_UTMPX_H
39 
40 #include <utmpx.h>
41 #define SH_UTMP_S utmpx
42 #undef  ut_name
43 #define ut_name ut_user
44 #ifdef HAVE_UTXTIME
45 #undef  ut_time
46 #define ut_time        ut_xtime
47 #else
48 #undef  ut_time
49 #define ut_time        ut_tv.tv_sec
50 #endif
51 
52 #else
53 
54 #include <utmp.h>
55 #define SH_UTMP_S utmp
56 
57 #endif
58 
59 
60 #if TIME_WITH_SYS_TIME
61 #include <sys/time.h>
62 #include <time.h>
63 #else
64 #if HAVE_SYS_TIME_H
65 #include <sys/time.h>
66 #else
67 #include <time.h>
68 #endif
69 #endif
70 
71 
72 #define SH_LTRACK_VERSION 1
73 
74 #define SH_LTRACK_USIZE  32
75 #define SH_LTRACK_HSIZE 256
76 /* One hour    (15 deg)  */
77 #define SH_LTRACK_HTRES  24
78 /* Ten minutes (2.5 deg) */
79 #define SH_LTRACK_GTRES 144
80 
81 /* Avoid compiling against lmath by including result tables for sin, cos
82  */
83 const double sintab_htres[SH_LTRACK_HTRES] = {
84  0.13052619222005157340,  0.38268343236508978178,  0.60876142900872065589,  0.79335334029123516508,  0.92387953251128673848,  0.99144486137381038215,
85  0.99144486137381038215,  0.92387953251128673848,  0.79335334029123516508,  0.60876142900872087793,  0.38268343236508989280,  0.13052619222005157340,
86 -0.13052619222005132360, -0.38268343236508967076, -0.60876142900872065589, -0.79335334029123494304, -0.92387953251128651644, -0.99144486137381038215,
87 -0.99144486137381049318, -0.92387953251128662746, -0.79335334029123516508, -0.60876142900872087793, -0.38268343236509039240, -0.13052619222005168442,
88 };
89 const double costab_htres[SH_LTRACK_HTRES] = {
90  0.99144486137381038215,  0.92387953251128673848,  0.79335334029123516508,  0.60876142900872065589,  0.38268343236508983729,  0.13052619222005171218,
91 -0.13052619222005160116, -0.38268343236508972627, -0.60876142900872065589, -0.79335334029123505406, -0.92387953251128673848, -0.99144486137381038215,
92 -0.99144486137381049318, -0.92387953251128684951, -0.79335334029123516508, -0.60876142900872087793, -0.38268343236509033689, -0.13052619222005162891,
93  0.13052619222005126809,  0.38268343236509000382,  0.60876142900872054486,  0.79335334029123494304,  0.92387953251128651644,  0.99144486137381038215,
94 };
95 const double sintab_gtres[SH_LTRACK_GTRES] = {
96  0.02181488503456112046,  0.06540312923014306168,  0.10886687485196457070,  0.15212338618991669281,  0.19509032201612824808,  0.23768589232617309825,
97  0.27982901403099208482,  0.32143946530316158672,  0.36243803828370163567,  0.40274668985873718352,  0.44228869021900124592,  0.48098876891938763256,
98  0.51877325816052144436,  0.55557023301960217765,  0.59130964836358235193,  0.62592347218405908205,  0.65934581510006884386,  0.69151305578226940352,
99  0.72236396205975550444,  0.75183980747897738439,  0.77988448309288171956,  0.80644460426748254545,  0.83146961230254523567,  0.85491187067294649449,
100  0.87672675570750768781,  0.89687274153268836674,  0.91531147911944710227,  0.93200786928279844012,  0.94693012949510557696,  0.96004985438592871372,
101  0.97134206981326143282,  0.98078528040323043058,  0.98836151046776066220,  0.99405633822231964647,  0.99785892323860347908,  0.99976202707990913243,
102  0.99976202707990913243,  0.99785892323860347908,  0.99405633822231964647,  0.98836151046776066220,  0.98078528040323043058,  0.97134206981326143282,
103  0.96004985438592871372,  0.94693012949510568799,  0.93200786928279855115,  0.91531147911944721329,  0.89687274153268836674,  0.87672675570750779883,
104  0.85491187067294671653,  0.83146961230254545772,  0.80644460426748254545,  0.77988448309288183058,  0.75183980747897738439,  0.72236396205975561546,
105  0.69151305578226951454,  0.65934581510006895488,  0.62592347218405919307,  0.59130964836358257397,  0.55557023301960217765,  0.51877325816052133334,
106  0.48098876891938763256,  0.44228869021900130143,  0.40274668985873729454,  0.36243803828370174669,  0.32143946530316175325,  0.27982901403099230686,
107  0.23768589232617337581,  0.19509032201612860891,  0.15212338618991663730,  0.10886687485196457070,  0.06540312923014311719,  0.02181488503456121761,
108 -0.02181488503456097475, -0.06540312923014286739, -0.10886687485196432090, -0.15212338618991641526, -0.19509032201612835911, -0.23768589232617312601,
109 -0.27982901403099202930, -0.32143946530316153121, -0.36243803828370152464, -0.40274668985873707250, -0.44228869021900107938, -0.48098876891938741052,
110 -0.51877325816052122232, -0.55557023301960195560, -0.59130964836358235193, -0.62592347218405908205, -0.65934581510006884386, -0.69151305578226929249,
111 -0.72236396205975550444, -0.75183980747897727337, -0.77988448309288194160, -0.80644460426748265647, -0.83146961230254523567, -0.85491187067294660551,
112 -0.87672675570750768781, -0.89687274153268825572, -0.91531147911944710227, -0.93200786928279844012, -0.94693012949510557696, -0.96004985438592860270,
113 -0.97134206981326132180, -0.98078528040323031956, -0.98836151046776066220, -0.99405633822231953545, -0.99785892323860347908, -0.99976202707990913243,
114 -0.99976202707990913243, -0.99785892323860347908, -0.99405633822231964647, -0.98836151046776066220, -0.98078528040323043058, -0.97134206981326143282,
115 -0.96004985438592871372, -0.94693012949510568799, -0.93200786928279855115, -0.91531147911944721329, -0.89687274153268847776, -0.87672675570750790985,
116 -0.85491187067294682755, -0.83146961230254545772, -0.80644460426748287851, -0.77988448309288216365, -0.75183980747897782848, -0.72236396205975605955,
117 -0.69151305578226918147, -0.65934581510006873284, -0.62592347218405897102, -0.59130964836358235193, -0.55557023301960217765, -0.51877325816052144436,
118 -0.48098876891938774358, -0.44228869021900141245, -0.40274668985873740557, -0.36243803828370185771, -0.32143946530316186427, -0.27982901403099241788,
119 -0.23768589232617348683, -0.19509032201612871993, -0.15212338618991719241, -0.10886687485196513969, -0.06540312923014367230, -0.02181488503456178660
120 };
121 const double costab_gtres[SH_LTRACK_GTRES] = {
122  0.99976202707990913243,  0.99785892323860347908,  0.99405633822231964647,  0.98836151046776066220,  0.98078528040323043058,  0.97134206981326143282,
123  0.96004985438592871372,  0.94693012949510568799,  0.93200786928279855115,  0.91531147911944721329,  0.89687274153268836674,  0.87672675570750768781,
124  0.85491187067294660551,  0.83146961230254523567,  0.80644460426748265647,  0.77988448309288183058,  0.75183980747897738439,  0.72236396205975561546,
125  0.69151305578226940352,  0.65934581510006884386,  0.62592347218405908205,  0.59130964836358235193,  0.55557023301960228867,  0.51877325816052155538,
126  0.48098876891938774358,  0.44228869021900124592,  0.40274668985873723903,  0.36243803828370169118,  0.32143946530316169774,  0.27982901403099202930,
127  0.23768589232617309825,  0.19509032201612833135,  0.15212338618991680383,  0.10886687485196473724,  0.06540312923014304780,  0.02181488503456115863,
128 -0.02181488503456103373, -0.06540312923014292290, -0.10886687485196461234, -0.15212338618991669281, -0.19509032201612819257, -0.23768589232617298723,
129 -0.27982901403099191828, -0.32143946530316158672, -0.36243803828370158016, -0.40274668985873712801, -0.44228869021900113490, -0.48098876891938746603,
130 -0.51877325816052122232, -0.55557023301960195560, -0.59130964836358246295, -0.62592347218405908205, -0.65934581510006884386, -0.69151305578226929249,
131 -0.72236396205975550444, -0.75183980747897727337, -0.77988448309288160853, -0.80644460426748243442, -0.83146961230254534669, -0.85491187067294660551,
132 -0.87672675570750768781, -0.89687274153268825572, -0.91531147911944710227, -0.93200786928279844012, -0.94693012949510557696, -0.96004985438592860270,
133 -0.97134206981326132180, -0.98078528040323043058, -0.98836151046776066220, -0.99405633822231964647, -0.99785892323860347908, -0.99976202707990913243,
134 -0.99976202707990913243, -0.99785892323860347908, -0.99405633822231964647, -0.98836151046776077322, -0.98078528040323043058, -0.97134206981326143282,
135 -0.96004985438592871372, -0.94693012949510568799, -0.93200786928279855115, -0.91531147911944721329, -0.89687274153268836674, -0.87672675570750779883,
136 -0.85491187067294671653, -0.83146961230254545772, -0.80644460426748254545, -0.77988448309288183058, -0.75183980747897749541, -0.72236396205975561546,
137 -0.69151305578226951454, -0.65934581510006906591, -0.62592347218405897102, -0.59130964836358224090, -0.55557023301960217765, -0.51877325816052144436,
138 -0.48098876891938768807, -0.44228869021900135694, -0.40274668985873735005, -0.36243803828370180220, -0.32143946530316180876, -0.27982901403099236237,
139 -0.23768589232617343132, -0.19509032201612866442, -0.15212338618991713690, -0.10886687485196507030, -0.06540312923014361679, -0.02181488503456172415,
140  0.02181488503456135639,  0.06540312923014325597,  0.10886687485196470948,  0.15212338618991677608,  0.19509032201612830359,  0.23768589232617307050,
141  0.27982901403099197379,  0.32143946530316147570,  0.36243803828370146913,  0.40274668985873701699,  0.44228869021900102387,  0.48098876891938735501,
142  0.51877325816052111129,  0.55557023301960184458,  0.59130964836358201886,  0.62592347218405863796,  0.65934581510006839977,  0.69151305578226895943,
143  0.72236396205975572649,  0.75183980747897749541,  0.77988448309288183058,  0.80644460426748254545,  0.83146961230254523567,  0.85491187067294660551,
144  0.87672675570750768781,  0.89687274153268825572,  0.91531147911944710227,  0.93200786928279844012,  0.94693012949510557696,  0.96004985438592860270,
145  0.97134206981326132180,  0.98078528040323031956,  0.98836151046776066220,  0.99405633822231953545,  0.99785892323860347908,  0.99976202707990913243
146 };
147 
148 struct sh_track_entry_data {
149   UINT64      last_login;
150   UINT32      array[SH_LTRACK_HTRES]; /* 1 h resolution */
151   char        hostname[SH_LTRACK_HSIZE];
152 };
153 
154 struct sh_track_entry {
155   struct sh_track_entry_data data;
156   struct sh_track_entry * next;
157 };
158 
159 struct sh_track_head {
160   UINT32 version;
161   UINT32 n_entries;
162   UINT64 last_login;
163   char   hostname[SH_LTRACK_HSIZE];
164   UINT32 array[SH_LTRACK_GTRES]; /* 10 min resolution */
165 };
166 
167 struct sh_track {
168   struct sh_track_head head;
169   struct sh_track_entry * list;
170 };
171 
172 
173 /* Returns zero/nonzero
174  */
get_bool(char * bitarray,unsigned int index)175 static int get_bool(char *bitarray, unsigned int index)
176 {
177   int bool;
178 
179   bitarray += index / 8; /* skip to char */
180   bool = (*bitarray & (1 << (index % 8)));
181 
182   return bool;
183 }
184 
set_bool(char * bitarray,unsigned int index,int bool)185 static void set_bool(char *bitarray, unsigned int index, int bool)
186 {
187   bitarray += index / 8; /* skip to char */
188   if (bool)
189     *bitarray |= 1 << (index % 8);
190   else
191     *bitarray &= ~(1 << (index % 8));
192   return;
193 }
194 
195 
build_path(const char * user)196 static char * build_path (const char * user)
197 {
198   char * ui;
199 
200   if (0 != sh_util_base64_enc_alloc (&ui, user, sl_strlen(user)))
201     {
202       char * path = sh_util_strconcat(DEFAULT_DATAROOT, "/", ui, NULL);
203 
204       SH_FREE(ui);
205       return path;
206     }
207   return NULL;
208 }
209 
destroy_loaded(struct sh_track * urecord)210 static void destroy_loaded(struct sh_track * urecord)
211 {
212   if (urecord)
213     {
214       struct sh_track_entry * entry = urecord->list;
215       struct sh_track_entry * entry_old;
216 
217       while(entry)
218 	{
219 	  entry_old = entry;
220 	  entry = entry->next;
221 	  SH_FREE(entry_old);
222 	}
223       SH_FREE(urecord);
224     }
225   return;
226 }
227 
load_data_int(char * path)228 static struct sh_track * load_data_int (char * path)
229 {
230   struct sh_track_head * uhead;
231   struct sh_track * urecord;
232 
233   urecord = SH_ALLOC(sizeof(struct sh_track));
234   memset(urecord, 0, sizeof(struct sh_track));
235 
236   uhead = &(urecord->head);
237   uhead->version = SH_LTRACK_VERSION;
238 
239   if (path)
240     {
241       FILE * fp = fopen(path, "rb");
242 
243       if (fp)
244 	{
245 	  size_t n;
246 
247 	  n = fread(uhead, sizeof(struct sh_track_head), 1, fp);
248 
249 	  if (n == 1)
250 	    {
251 	      struct sh_track_entry_data entry_data;
252 	      struct sh_track_entry * entry;
253 
254 	      while (1 == fread(&entry_data, sizeof(entry_data), 1, fp))
255 		{
256 		  entry = SH_ALLOC(sizeof(struct sh_track_entry));
257 		  memcpy(&(entry->data), &entry_data, sizeof(entry_data));
258 		  entry->next   = urecord->list;
259 		  urecord->list = entry;
260 		}
261 	    }
262 	  fclose(fp);
263 	}
264     }
265 
266   return urecord;
267 }
268 
load_data(const char * user)269 static struct sh_track * load_data (const char * user)
270 {
271   char * path = build_path (user);
272   struct sh_track * res = load_data_int (path);
273 
274   if (path)
275     SH_FREE(path);
276   return res;
277 }
278 
save_data_int(struct sh_track * urecord,char * path)279 static void save_data_int (struct sh_track * urecord, char * path)
280 {
281   mode_t mask;
282   FILE * fp;
283 
284   mask = umask(S_IWGRP | S_IWOTH);
285   fp = fopen(path, "wb");
286   (void) umask(mask);
287 
288   if (fp)
289     {
290       size_t n;
291 
292       n = fwrite(&(urecord->head), sizeof(struct sh_track_head), 1, fp);
293 
294       if (n == 1)
295 	{
296 	  struct sh_track_entry * entry = urecord->list;
297 
298 	  while (entry && (n > 0))
299 	    {
300 	      n = fwrite(&(entry->data), sizeof(struct sh_track_entry_data),
301 			 1, fp);
302 	      entry = entry->next;
303 	    }
304 	}
305       fclose(fp);
306     }
307   return;
308 }
309 
save_data(struct sh_track * urecord,const char * user)310 static void save_data (struct sh_track * urecord, const char * user)
311 {
312   char * path = build_path (user);
313 
314   if (path)
315     {
316       save_data_int (urecord, path);
317       SH_FREE(path);
318     }
319   return;
320 }
321 
322 /**************
323  *
324  * Configurable
325  *
326  **************/
327 
328 enum significance { SIG00, SIG01, SIG05 };
329 enum checklevel   { CHECK_NONE, CHECK_HOST, CHECK_DOMAIN };
330 enum days         { WORKDAYS = 0, SATURDAY, SUNDAY };
331 #define LTRACK_NDAYS 3
332 
333 static int sig_level    = SIG00;
334 static int check_level  = CHECK_NONE;
335 static int check_date   = S_FALSE;
336 
337 /* We use a bit array of SH_LTRACK_GTRES bits for allowed times
338  * (10 min resolution)
339  */
340 #define BITARRSIZ(a) ((a + 7) / 8)
341 
342 static int global_init  = S_FALSE;
343 static char global_dates[LTRACK_NDAYS][BITARRSIZ(SH_LTRACK_GTRES)];
344 
345 struct sh_track_dates {
346   char user[SH_LTRACK_USIZE];
347   char dates[LTRACK_NDAYS][BITARRSIZ(SH_LTRACK_GTRES)];
348   struct sh_track_dates * next;
349 };
350 struct sh_track_dates * user_dates = NULL;
351 
352 static int set_dates (char bitarray[][BITARRSIZ(SH_LTRACK_GTRES)],
353 		      unsigned int size, const char * defstr);
354 
sh_login_reset(void)355 void sh_login_reset (void)
356 {
357   int i, j;
358   struct sh_track_dates *u_old, *u;
359 
360   u          = user_dates;
361   user_dates = NULL;
362 
363   while(u)
364     {
365       u_old = u;
366       u     = u->next;
367       SH_FREE(u_old);
368     }
369 
370   for (j = 0; j < LTRACK_NDAYS; ++j)
371     {
372       for (i = 0; i < SH_LTRACK_GTRES; ++i)
373 	{
374 	  set_bool(global_dates[j], i, 0);
375 	}
376     }
377   global_init = S_FALSE;
378 
379   sig_level    = SIG00;
380   check_level  = CHECK_NONE;
381   check_date   = S_FALSE;
382 
383   return;
384 }
385 
sh_login_set_def_allow(const char * c)386 int sh_login_set_def_allow(const char * c)
387 {
388   int res = set_dates(global_dates, SH_LTRACK_GTRES, c);
389 
390   if (res == 0)
391     {
392       check_date   = S_TRUE;
393       global_init  = S_TRUE;
394     }
395   return res;
396 }
397 
find_user(const char * user)398 static struct sh_track_dates * find_user(const char * user)
399 {
400   struct sh_track_dates * u = user_dates;
401 
402   while(u)
403     {
404       if (0 == strcmp(user, u->user))
405 	{
406 	  return u;
407 	}
408       u = u->next;
409     }
410   return NULL;
411 }
412 
sh_login_set_user_allow(const char * c)413 int sh_login_set_user_allow(const char * c)
414 {
415   unsigned int i = 0;
416   const char *p = c;
417   char user[SH_LTRACK_USIZE];
418 
419   struct sh_track_dates * u;
420 
421   while (p && *p && *p != ':' && *p != ' ' && *p != '\t')
422     {
423       user[i] = *p; ++p; ++i;
424 
425       if (i == SH_LTRACK_USIZE)
426 	return -1;
427     }
428 
429   while (p && *p && (*p == ' ' || *p == '\t')) ++p;
430 
431   if (p && *p && (i < SH_LTRACK_USIZE) && (*p == ':'))
432     {
433       user[i] = '\0';
434 
435       ++p; while (*p && (*p == ' ' || *p == '\t')) ++p;
436 
437       if (*p)
438 	{
439 	  int res;
440 	  int flag = 0;
441 
442 	  u = find_user(user);
443 
444 	  if (!u)
445 	    {
446 	      u = SH_ALLOC(sizeof(struct sh_track_dates));
447 	      memset(u, 0, sizeof(struct sh_track_dates));
448 	      sl_strlcpy(u->user, user, SH_LTRACK_USIZE);
449 	      flag = 1;
450 	    }
451 
452 	  res = set_dates(u->dates, SH_LTRACK_GTRES, p);
453 	  if (res != 0)
454 	    {
455 	      if (flag == 1)
456 		SH_FREE(u);
457 	      return -1;
458 	    }
459 
460 	  if (flag == 1)
461 	    {
462 	      u->next    = user_dates;
463 	      user_dates = u;
464 	    }
465 
466 	  check_date = S_TRUE;
467 	  return 0;
468 	}
469     }
470   return -1;
471 }
472 
sh_login_set_siglevel(const char * c)473 int sh_login_set_siglevel(const char * c)
474 {
475   int ret = sh_util_flagval(c, &sig_level);
476 
477   if (ret == 0)
478     {
479       sig_level = (sig_level == S_FALSE) ? SIG00 : SIG01;
480       return 0;
481     }
482   else
483     {
484       if (0 == strcmp(c, _("paranoid")))
485 	{
486 	  sig_level = SIG05;
487 	  return 0;
488 	}
489     }
490   sig_level = SIG00;
491   return -1;
492 }
493 
sh_login_set_checklevel(const char * c)494 int sh_login_set_checklevel(const char * c)
495 {
496   int ret = sh_util_flagval(c, &check_level);
497 
498   if (ret == 0)
499     {
500       check_level = (check_level == S_FALSE) ? CHECK_NONE : CHECK_HOST;
501       return 0;
502     }
503   else
504     {
505       if (0 == strcmp(c, _("domain")))
506 	{
507 	  check_level = CHECK_DOMAIN;
508 	  return 0;
509 	}
510     }
511   check_level = CHECK_NONE;
512   return -1;
513 }
514 
eval_range(char * bitarray,unsigned int size,char * def)515 static int eval_range(char * bitarray, unsigned int size, char * def)
516 {
517   unsigned int h1, m1, h2, m2;
518 
519   int res = sscanf(def, "%d:%d - %d:%d", &h1, &m1, &h2, &m2);
520 
521   if (res == 4)
522     {
523       unsigned int t1 = 3600*h1 + 60*m1;
524       unsigned int t2 = 3600*h2 + 60*m2;
525       int hres        = (60*60*24)/size;
526       unsigned int i;
527 
528       if (t1 > t2 || t1 > 86340 || t2 > 86340)
529 	return -1;
530 
531       t1  = t1 / hres;
532       t2  = t2 / hres;
533       t1  = (t1 < size) ? t1 : (size-1);
534       t2  = (t2 < size) ? t2 : (size-1);
535 
536       for (i = t1; i <= t2; ++i)
537 	{
538 	  set_bool(bitarray, i, 1);
539 	}
540       return 0;
541     }
542   return -1;
543 }
544 
set_ranges(char * bitarray,unsigned int size,char ** splits,unsigned int nfields)545 static int set_ranges(char * bitarray, unsigned int size,
546 		      char ** splits, unsigned int nfields)
547 {
548   unsigned int i;
549   int retval = 0;
550 
551   for (i = 0; i < nfields; ++i)
552     {
553       char * range = &(splits[i][0]);
554 
555       if (0 != eval_range(bitarray, size, range))
556 	retval = -1;
557     }
558   return retval;
559 }
560 
561 /* 'always', 'never', workdays(list of ranges), (sun|satur)day(list of ranges)
562  */
set_dates(char bitarray[][BITARRSIZ (SH_LTRACK_GTRES)],unsigned int size,const char * defstr)563 static int set_dates (char bitarray[][BITARRSIZ(SH_LTRACK_GTRES)],
564 		      unsigned int size,
565 		      const char * defstr)
566 {
567   unsigned int i, j;
568   int retval = -1;
569 
570   if (0 == strcmp(_("always"), defstr))
571     {
572       for (j = 0; j < LTRACK_NDAYS; ++j)
573 	for (i = 0; i < size; ++i)
574 	  set_bool(bitarray[j], i, 1);
575       retval = 0;
576     }
577   else if (0 == strcmp(_("never"), defstr))
578     {
579       for (j = 0; j < LTRACK_NDAYS; ++j)
580 	for (i = 0; i < size; ++i)
581 	  set_bool(bitarray[j], i, 0);
582       retval = 0;
583     }
584   else
585     {
586       unsigned int nfields = 24; /* list of ranges */
587       size_t       lengths[24];
588       char *       new    = NULL;
589       char **      splits = NULL;
590 
591       if      (0 == strncmp(_("workdays"), defstr, 7))
592 	{
593 	  new    = sh_util_strdup(defstr);
594 	  splits = split_array_braced(new, _("workdays"),
595 				      &nfields, lengths);
596 	  j = WORKDAYS;
597 	}
598       else if (0 == strncmp(_("saturday"), defstr, 8))
599 	{
600 	  new    = sh_util_strdup(defstr);
601 	  splits = split_array_braced(new, _("saturday"),
602 				      &nfields, lengths);
603 	  j = SATURDAY;
604 	}
605       else if (0 == strncmp(_("sunday"), defstr, 6))
606 	{
607 	  new    = sh_util_strdup(defstr);
608 	  splits = split_array_braced(new, _("sunday"),
609 				      &nfields, lengths);
610 	  j = SUNDAY;
611 	}
612       else
613 	{
614 	  return -1;
615 	}
616 
617       if (new && splits && nfields > 0)
618 	{
619 	  retval = set_ranges(bitarray[j], size, splits, nfields);
620 	}
621 
622       if (new) SH_FREE(new);
623     }
624   return retval;
625 }
626 
627 
628 
629 /**************
630  *
631  * Report
632  *
633  **************/
634 
report_generic(char * file,int line,const char * user,time_t time,const char * host,int what)635 void report_generic(char * file, int line,
636 		    const char * user, time_t time, const char * host, int what)
637 {
638   char   ttt[TIM_MAX];
639 
640   SH_MUTEX_LOCK(mutex_thread_nolog);
641   (void) sh_unix_time (time, ttt, TIM_MAX);
642   sh_error_handle ((-1), file, line, 0, what,
643 		   user, host, ttt);
644   SH_MUTEX_UNLOCK(mutex_thread_nolog);
645   return;
646 }
647 
report_bad_date(char * file,int line,const char * user,time_t time,const char * host)648 void report_bad_date(char * file, int line,
649 		     const char *user, time_t time, const char * host)
650 {
651   report_generic(file, line, user, time, host, MSG_UT_BAD);
652 }
653 
report_first(char * file,int line,const char * user,time_t time,const char * host)654 void report_first(char * file, int line,
655 		  const char *user, time_t time, const char * host)
656 {
657   report_generic(file, line, user, time, host, MSG_UT_FIRST);
658 }
659 
report_outlier(char * file,int line,const char * user,time_t time,const char * host)660 void report_outlier(char * file, int line,
661 		    const char *user, time_t time, const char * host)
662 {
663   report_generic(file, line, user, time, host, MSG_UT_OUTLIER);
664 }
665 
666 /**************
667  *
668  * Dates
669  *
670  **************/
671 
check_login_date(const char * user,unsigned int index,int wday)672 static int check_login_date(const char * user, unsigned int index, int wday)
673 {
674   unsigned int i, j;
675   struct sh_track_dates * allowed = NULL;
676   int day;
677 
678   /* Use an intermediate array 'char* b[m]' to cast 'char a[m][n]' to 'char** c' */
679   char * aux[LTRACK_NDAYS];
680   char **good = (char **) aux;
681 
682   for (i = 0; i < LTRACK_NDAYS; ++i)
683     {
684       aux[i] = (char *) &global_dates[i][0];
685       /* + i * BITARRSIZ(SH_LTRACK_GTRES); */
686     }
687 
688   if (wday > 0 && wday < 6)
689     day = WORKDAYS;
690   else if (wday == 6)
691     day = SATURDAY;
692   else
693     day = SUNDAY;
694 
695   if (check_date != S_FALSE)
696     {
697       if (S_FALSE == global_init)
698 	{
699 	  for (j = 0; j < LTRACK_NDAYS; ++j)
700 	    {
701 	      for (i = 0; i < SH_LTRACK_GTRES; ++i)
702 		set_bool(global_dates[j], i, 1);
703 	    }
704 	  global_init = S_TRUE;
705 	}
706 
707       if (user) {
708 	allowed = find_user(user);
709       }
710 
711       if (allowed)
712 	{
713 	  for (i = 0; i < LTRACK_NDAYS; ++i)
714 	    {
715 	      aux[i] = (char *)&(allowed->dates)[i][0];
716 	      /* + i*BITARRSIZ(SH_LTRACK_GTRES); */
717 	    }
718 	}
719 
720       if (0 == get_bool(good[day], index))
721 	{
722 	  return -1;
723 	}
724     }
725   return 0;
726 }
727 
728 /**************
729  *
730  * Statistics
731  *
732  **************/
733 
734 /* Compute sqrt(s) using the babylonian algorithm
735  * (to avoid linking with -lm).
736  */
sh_sqrt(double s)737 static double sh_sqrt(double s)
738 {
739   double eps = 1.0e-6;
740   double x0  = 1.0;
741   double xs  = s;
742 
743   double diff = xs - x0;
744   diff = (diff > 0.0) ? diff : -diff;
745 
746   while (diff > eps)
747     {
748       xs = x0;
749       x0 = 0.5 * (x0 + (s/x0));
750       diff = xs - x0;
751       diff = (diff > 0.0) ? diff : -diff;
752     }
753   return x0;
754 }
755 
M_crit(int n,int flag)756 static double M_crit(int n, int flag)
757 {
758 #define SH_MCSIZE 10
759   const double M_05[SH_MCSIZE] = { 0.975, 0.918, 0.855, 0.794, 0.739, 0.690, 0.647, 0.577, 0.497, 0.406 };
760   const double M_01[SH_MCSIZE] = { 0.995, 0.970, 0.934, 0.891, 0.845, 0.799, 0.760, 0.688, 0.603, 0.498 };
761   const int    M_nn[SH_MCSIZE] = {     4,     5,     6,     7,     8,     9,    10,    12,    15,    20 };
762 
763   if (n > M_nn[SH_MCSIZE-1])
764     {
765       return ((flag == SIG05) ? M_05[SH_MCSIZE-1] : M_01[SH_MCSIZE-1]);
766     }
767   else
768     {
769       unsigned int i;
770 
771       for (i = 1; i < SH_MCSIZE; ++i)
772 	{
773 	  if (n < M_nn[i])
774 	    {
775 	      return ((flag == SIG05) ? M_05[i-1] : M_01[i-1]);
776 	    }
777 	}
778     }
779 
780   return ((flag == SIG05) ? M_05[SH_MCSIZE-1] : M_01[SH_MCSIZE-1]);
781 }
782 
check_statistics(unsigned int index,UINT32 * array,unsigned int size,const double * costab,const double * sintab)783 static int check_statistics (unsigned int index, UINT32 * array, unsigned int size,
784 			     const double * costab, const double * sintab)
785 {
786   double C = 0.0;
787   double S = 0.0;
788   double R, Rk, M;
789 
790   unsigned int i, n = 0;
791 
792   if (sig_level != SIG00)
793     {
794       for (i = 0; i < size; ++i)
795 	{
796 	  n += array[i];
797 	  C += (array[i] * costab[i]);
798 	  S += (array[i] * sintab[i]);
799 	}
800 
801       if (n > 2) /* current is at least 4th datapoint */
802 	{
803 	  R = sh_sqrt(S*S + C*C);
804 
805 	  C += array[index] * costab[index];
806 	  S += array[index] * sintab[index];
807 	  Rk = sh_sqrt(S*S + C*C);
808 	  ++n;
809 
810 	  M  = (Rk - R + 1.0)/((double)n - R);
811 
812 	  if (M > M_crit(n, sig_level))
813 	    {
814 	      return -1;
815 	    }
816 	}
817     }
818   return 0;
819 }
820 
stripped_hostname(const char * host)821 static char * stripped_hostname (const char * host)
822 {
823   char *p, *q;
824 
825   if (sh_ipvx_is_numeric(host))
826     {
827       p = sh_util_strdup(host);
828       q = strrchr(p, '.');
829       if (q)
830 	{
831 	  *q = '\0';
832 	  q = strrchr(p, '.');
833 	  if (q)
834 	    {
835 	      *q = '\0';
836 	    }
837 	}
838     }
839   else
840     {
841       q = strchr(host, '.');
842       if (q && *q)
843 	{
844 	  ++q;
845 	  p = sh_util_strdup(q);
846 	}
847       else
848 	{
849 	  p = sh_util_strdup(host);
850 	}
851     }
852   return p;
853 }
854 
time_to_index(struct tm * tp,int nbin)855 static unsigned int time_to_index(struct tm * tp, int nbin)
856 {
857   int hres  = (60*60*24)/nbin;
858   int index = tp->tm_hour * 3600 + tp->tm_min * 60 + tp->tm_sec;
859   index  = index / hres;
860   index  = (index < nbin) ? index : (nbin-1);
861 
862   return index;
863 }
864 
check_host(struct sh_track_entry * list,const char * user,time_t time,const char * host,struct tm * tp)865 static struct sh_track_entry * check_host(struct sh_track_entry * list,
866 					  const char * user, time_t time, const char * host,
867 					  struct tm * tp)
868 {
869   unsigned int    index = time_to_index(tp, SH_LTRACK_HTRES);
870   struct sh_track_entry * entry = list;
871 
872   char * p = NULL;
873   const char * q;
874 
875   if (check_level == CHECK_DOMAIN)
876     {
877       p = stripped_hostname(host);
878       q = p;
879     }
880   else
881     {
882       q = host;
883     }
884 
885   while (entry)
886     {
887       if (0 == strncmp(q, (entry->data).hostname, SH_LTRACK_HSIZE))
888 	break;
889       entry = entry->next;
890     }
891 
892   if (entry)
893     {
894       int isAlert;
895 
896       (entry->data).last_login    = time;
897 
898       /* Check host statistics here
899        */
900       isAlert = check_statistics (index, (entry->data).array, SH_LTRACK_HTRES,
901 				  costab_htres, sintab_htres);
902 
903       if (isAlert != 0)
904 	{
905 	  report_outlier(FIL__, __LINE__, user, time, host);
906 	}
907 
908       /* Update array afterwards
909        */
910       (entry->data).array[index] += 1;
911     }
912   else
913     {
914       entry = SH_ALLOC(sizeof(struct sh_track_entry));
915       memset(entry, 0, sizeof(struct sh_track_entry));
916       (entry->data).last_login    = time;
917       (entry->data).array[index]  = 1;
918       sl_strlcpy((entry->data).hostname, q, SH_LTRACK_HSIZE);
919 
920       /* Report first login from this host
921        */
922       if (check_level != CHECK_NONE)
923 	{
924 	  report_first (FIL__, __LINE__, user, time, host);
925 	}
926 
927       if (p)
928 	SH_FREE(p);
929       return entry;
930     }
931 
932   if (p)
933     SH_FREE(p);
934   return NULL;
935 }
936 
937 /********************************************************
938  *
939  * Public Function
940  *
941  ********************************************************/
942 
sh_ltrack_check(struct SH_UTMP_S * ut)943 void sh_ltrack_check(struct SH_UTMP_S * ut)
944 {
945   int gres;
946   const char * user;
947   time_t time;
948 #if defined(HAVE_UTHOST)
949   const char * host;
950 #else
951   const char * host;
952 #endif
953   struct sh_track * urecord;
954   time_t last_login;
955 
956   /* Just return if we are not supposed to do anything
957    */
958   if (sig_level == SIG00 && check_level == CHECK_NONE && check_date == S_FALSE)
959     return;
960 
961 
962 #if defined(HAVE_UTHOST)
963   host = ut->ut_host;
964 #else
965   host = sh_util_strdup(_("unknown"));
966 #endif
967   time = ut->ut_time;
968   user = ut->ut_name;
969 
970   gres  = (60*60*24)/SH_LTRACK_GTRES;
971 
972   urecord    = load_data(user);
973   last_login = (urecord->head).last_login;
974 
975   if (   last_login < time &&
976 	 ( (time - last_login) >= gres ||
977 	   0 != strcmp(host, (urecord->head).hostname)
978 	   )
979 	 )
980     {
981       struct tm ts;
982       unsigned int  index;
983       int isAlert;
984       struct sh_track_entry * entry;
985 
986       (urecord->head).last_login = time;
987       sl_strlcpy((urecord->head).hostname, host, SH_LTRACK_HSIZE);
988       (urecord->head).n_entries += 1;
989 
990       memcpy(&ts, localtime(&time), sizeof(struct tm));
991       index = time_to_index(&ts, SH_LTRACK_GTRES);
992 
993       /* Check global statistics here
994        */
995       isAlert = check_statistics (index, (urecord->head).array,
996 				  SH_LTRACK_GTRES,
997 				  costab_gtres, sintab_gtres);
998 
999       if (isAlert != 0)
1000 	{
1001 	  report_outlier(FIL__, __LINE__, user, time, host);
1002 	}
1003 
1004 
1005       if (check_date != S_FALSE)
1006 	{
1007 	  int isBad = check_login_date(user, index, ts.tm_wday);
1008 
1009 	  if (isBad != 0)
1010 	    {
1011 	      report_bad_date(FIL__, __LINE__, user, time, host);
1012 	    }
1013 	}
1014 
1015       /* Update array afterwards
1016        */
1017       (urecord->head).array[index] += 1;
1018 
1019       entry = check_host(urecord->list, user, time, host, &ts);
1020       if (entry)
1021 	{
1022 	  entry->next   = urecord->list;
1023 	  urecord->list = entry;
1024 	}
1025 
1026       save_data(urecord, user);
1027     }
1028 
1029   destroy_loaded(urecord);
1030 
1031 #if !defined(HAVE_UTHOST)
1032   SH_FREE(host);
1033 #endif
1034   return;
1035 }
1036 
1037 #ifdef SH_CUTEST
1038 #include <stdlib.h>
1039 #include <sys/types.h>
1040 #include <unistd.h>
1041 
1042 #include "CuTest.h"
1043 
Test_login(CuTest * tc)1044 void Test_login (CuTest *tc) {
1045   char bitarr[10] = { 0,0,0,0,0,0,0,0,0,128 };
1046   unsigned int i;
1047   int j, k;
1048   char buf[1024];
1049   char *p, *q;
1050   size_t l1, l2;
1051 
1052   /* Check bitarray */
1053 
1054   for (i = 0; i < 72; ++i)
1055     {
1056       set_bool(bitarr, i, 1);
1057     }
1058   for (i = 72; i < 80; ++i)
1059     {
1060       set_bool(bitarr, i, 0);
1061     }
1062   for (i = 0; i < 80; ++i)
1063     {
1064       j = get_bool(bitarr, i);
1065       if (i < 72)
1066 	CuAssertTrue(tc, j > 0);
1067       else
1068 	CuAssertIntEquals(tc, 0, j);
1069     }
1070 
1071   /* check build_path */
1072 
1073   j = sl_strlcpy(buf, DEFAULT_DATAROOT, sizeof(buf));
1074   CuAssertIntEquals(tc, 0, j);
1075 
1076   p = build_path("rainer");
1077   q = sh_util_dirname(p);
1078   j = strncmp(buf, q, strlen(buf));
1079   l1 = strlen(buf); l2 = strlen(q);
1080   CuAssertTrue(tc, l2 >= l1);
1081   CuAssertIntEquals(tc, 0, j);
1082 
1083   q = sh_util_basename(p);
1084   CuAssertStrEquals(tc, q, "cmFpbmVy");
1085 
1086   { /* Check load/save of user data */
1087     struct sh_track urecord, *precord;
1088     struct sh_track_entry uentry0, *pentry;
1089     struct sh_track_entry uentry1;
1090 
1091     urecord.head.version   = 40;
1092     urecord.head.n_entries = 41;
1093     urecord.head.last_login = 42;
1094     for (i = 0; i < SH_LTRACK_GTRES; ++i)
1095       urecord.head.array[i] = 0;
1096     urecord.head.array[30] = 30;
1097 
1098     urecord.list = &uentry0;
1099     uentry0.next = &uentry1;
1100     uentry1.next = NULL;
1101 
1102     uentry0.data.last_login = 52;
1103     strcpy(uentry0.data.hostname, "host0");
1104     for (i = 0; i < SH_LTRACK_HTRES; ++i)
1105       uentry0.data.array[i] = 0;
1106     uentry0.data.array[5] = 50;
1107 
1108     uentry1.data.last_login = 62;
1109     strcpy(uentry1.data.hostname, "host1");
1110     for (i = 0; i < SH_LTRACK_HTRES; ++i)
1111       uentry1.data.array[i] = 0;
1112     uentry1.data.array[6] = 60;
1113 
1114     snprintf(buf, sizeof(buf), "cutest_%06d", (int) getpid());
1115 
1116     save_data_int(&urecord, buf);
1117 
1118     precord = load_data_int(buf);
1119 
1120     CuAssertIntEquals(tc, urecord.head.version, (precord->head).version);
1121     CuAssertIntEquals(tc, urecord.head.n_entries, (precord->head).n_entries);
1122     CuAssertIntEquals(tc, urecord.head.last_login, (precord->head).last_login);
1123     for (i = 0; i < SH_LTRACK_GTRES; ++i)
1124       CuAssertIntEquals(tc, urecord.head.array[i], (precord->head).array[i]);
1125 
1126     CuAssertPtrNotNull(tc, precord->list);
1127     pentry = precord->list;
1128     CuAssertIntEquals(tc, uentry1.data.last_login, (pentry->data).last_login);
1129     CuAssertStrEquals(tc, uentry1.data.hostname, (pentry->data).hostname);
1130     for (i = 0; i < SH_LTRACK_HTRES; ++i)
1131       CuAssertIntEquals(tc, uentry1.data.array[i], (pentry->data).array[i]);
1132 
1133     CuAssertPtrNotNull(tc, pentry->next);
1134     pentry = pentry->next;
1135     CuAssertIntEquals(tc, uentry0.data.last_login, (pentry->data).last_login);
1136     CuAssertStrEquals(tc, uentry0.data.hostname, (pentry->data).hostname);
1137     for (i = 0; i < SH_LTRACK_HTRES; ++i)
1138       CuAssertIntEquals(tc, uentry0.data.array[i], (pentry->data).array[i]);
1139 
1140     CuAssertPtrEquals(tc, pentry->next, NULL);
1141     destroy_loaded(precord);
1142     unlink(buf);
1143 
1144     precord = load_data_int("supacalifragilistic");
1145     CuAssertPtrNotNull(tc, precord);
1146     CuAssertPtrEquals(tc, precord->list, NULL);
1147     CuAssertIntEquals(tc, SH_LTRACK_VERSION, (precord->head).version);
1148     CuAssertIntEquals(tc, 0, (precord->head).n_entries);
1149     CuAssertIntEquals(tc, 0, (precord->head).last_login);
1150     for (i = 0; i < SH_LTRACK_GTRES; ++i)
1151       CuAssertIntEquals(tc, 0, (precord->head).array[i]);
1152     destroy_loaded(precord);
1153 
1154     precord = load_data_int(NULL);
1155     CuAssertPtrNotNull(tc, precord);
1156     CuAssertPtrEquals(tc, precord->list, NULL);
1157     CuAssertIntEquals(tc, SH_LTRACK_VERSION, (precord->head).version);
1158     CuAssertIntEquals(tc, 0, (precord->head).n_entries);
1159     CuAssertIntEquals(tc, 0, (precord->head).last_login);
1160     for (i = 0; i < SH_LTRACK_GTRES; ++i)
1161       CuAssertIntEquals(tc, 0, (precord->head).array[i]);
1162     destroy_loaded(precord);
1163   }
1164 
1165   /* check configuration */
1166 
1167   j = sh_login_set_siglevel("duh");
1168   CuAssertIntEquals(tc, -1, j);
1169   CuAssertIntEquals(tc, SIG00, sig_level);
1170 
1171   j = sh_login_set_siglevel("yes");
1172   CuAssertIntEquals(tc, 0, j);
1173   CuAssertIntEquals(tc, SIG01, sig_level);
1174   j = sh_login_set_siglevel("no");
1175   CuAssertIntEquals(tc, 0, j);
1176   CuAssertIntEquals(tc, SIG00, sig_level);
1177   j = sh_login_set_siglevel("paranoid");
1178   CuAssertIntEquals(tc, 0, j);
1179   CuAssertIntEquals(tc, SIG05, sig_level);
1180 
1181   j = sh_login_set_checklevel("duh");
1182   CuAssertIntEquals(tc, -1, j);
1183   CuAssertIntEquals(tc, CHECK_NONE, check_level);
1184 
1185   j = sh_login_set_checklevel("yes");
1186   CuAssertIntEquals(tc, 0, j);
1187   CuAssertIntEquals(tc, CHECK_HOST, check_level);
1188   j = sh_login_set_checklevel("no");
1189   CuAssertIntEquals(tc, 0, j);
1190   CuAssertIntEquals(tc, CHECK_NONE, check_level);
1191   j = sh_login_set_checklevel("domain");
1192   CuAssertIntEquals(tc, 0, j);
1193   CuAssertIntEquals(tc, CHECK_DOMAIN, check_level);
1194 
1195   j = sh_login_set_def_allow("always");
1196   CuAssertIntEquals(tc, 0, j);
1197   for (j = 0; j < LTRACK_NDAYS; ++j)
1198     {
1199       for (i = 0; i < SH_LTRACK_GTRES; ++i)
1200 	{
1201 	  k = get_bool(global_dates[j], i);
1202 	  CuAssertTrue(tc, k > 0);
1203 	}
1204     }
1205 
1206   j = sh_login_set_def_allow("never");
1207   CuAssertIntEquals(tc, 0, j);
1208   for (j = 0; j < LTRACK_NDAYS; ++j)
1209     {
1210       for (i = 0; i < SH_LTRACK_GTRES; ++i)
1211 	{
1212 	  k = get_bool(global_dates[j], i);
1213 	  CuAssertIntEquals(tc, 0, k);
1214 	}
1215     }
1216 
1217   j = sh_login_set_def_allow("workdays( 0:12-1:30, 07:30-18:29,23:30-23:59)");
1218   CuAssertIntEquals(tc, 0, j);
1219   for (j = 0; j < LTRACK_NDAYS; ++j)
1220     {
1221       for (i = 0; i < SH_LTRACK_GTRES; ++i)
1222 	{
1223 	  k = get_bool(global_dates[j], i);
1224 	  // fprintf(stderr, "%d: %d: %d\n", j, i, k);
1225 	  if (j == WORKDAYS)
1226 	    {
1227 	      if ( (i>=1 && i<=9) || (i>=45 && i <=110) || (i>=141 && i<=143))
1228 		CuAssertTrue(tc, k > 0);
1229 	      else
1230 		CuAssertIntEquals(tc, 0, k);
1231 	    }
1232 	  else
1233 	    {
1234 	      CuAssertIntEquals(tc, 0, k);
1235 	    }
1236 	}
1237     }
1238 
1239   j = sh_login_set_user_allow("rainer :workdays( 0:12-1:30, 07:30-18:29,23:30-23:59)");
1240   CuAssertIntEquals(tc, 0, j);
1241   j = sh_login_set_user_allow("rainer :saturday( 0:0-23:59)");
1242   CuAssertIntEquals(tc, 0, j);
1243   j = sh_login_set_user_allow("rain : workdays(0:12-1:30, 07:30-18:29,23:30-23:59)");
1244   CuAssertIntEquals(tc, 0, j);
1245   j = sh_login_set_user_allow("cat: workdays( 0:12-1:30, 07:30-18:29,23:30-23:59 )");
1246   CuAssertIntEquals(tc, 0, j);
1247   j = sh_login_set_user_allow("cat: sunday(0:00-23:59)");
1248   CuAssertIntEquals(tc, 0, j);
1249 
1250   {
1251     int count = 0;
1252     struct sh_track_dates * u = user_dates;
1253 
1254     CuAssertPtrNotNull(tc, u);
1255 
1256     do {
1257 
1258       if (count == 0) {
1259 	CuAssertStrEquals(tc, u->user, "cat");
1260 	CuAssertPtrNotNull(tc, u->next);
1261       }
1262       else if (count == 1) {
1263 	CuAssertStrEquals(tc, u->user, "rain");
1264 	CuAssertPtrNotNull(tc, u->next);
1265       }
1266       else if (count == 2) {
1267 	CuAssertStrEquals(tc, u->user, "rainer");
1268 	CuAssertPtrEquals(tc, u->next, NULL);
1269       }
1270 
1271       for (j = 0; j < LTRACK_NDAYS; ++j)
1272 	{
1273 	  for (i = 0; i < SH_LTRACK_GTRES; ++i)
1274 	    {
1275 	      k = get_bool(u->dates[j], i);
1276 	      // fprintf(stderr, "%d: %d: %d\n", j, i, k);
1277 	      if (j == WORKDAYS)
1278 		{
1279 		  if ( (i>=1 && i<=9) || (i>=45 && i <=110) ||
1280 		       (i>=141 && i<=143) )
1281 		    {
1282 		      CuAssertTrue(tc, k > 0);
1283 		    }
1284 		  else
1285 		    {
1286 		      CuAssertIntEquals(tc, 0, k);
1287 		    }
1288 		}
1289 	      else
1290 		{
1291 		  if ((count == 0 && j == SUNDAY) ||
1292 		      (count == 2 && j == SATURDAY))
1293 		    CuAssertTrue(tc, k > 0);
1294 		  else
1295 		    CuAssertIntEquals(tc, 0, k);
1296 		}
1297 	    }
1298 	}
1299 
1300       if (u->next == NULL)
1301 	break;
1302 
1303       u = u->next; ++count;
1304 
1305     } while (1 == 1);
1306   }
1307 
1308   sh_login_reset();
1309   CuAssertIntEquals(tc, SIG00, sig_level);
1310   CuAssertIntEquals(tc, CHECK_NONE, check_level);
1311 
1312   /* check dates */
1313 
1314   j = sh_login_set_def_allow("workdays( 0:12-1:30, 07:30-18:29,23:30-23:59)");
1315   CuAssertIntEquals(tc, 0, j);
1316 
1317   j = check_login_date("rainer", 0, 2);
1318   CuAssertIntEquals(tc, -1, j);
1319   j = check_login_date("rainer", 1, 2);
1320   CuAssertIntEquals(tc,  0, j);
1321   j = check_login_date("rainer",50, 3);
1322   CuAssertIntEquals(tc,  0, j);
1323   j = check_login_date("rainer",142, 5);
1324   CuAssertIntEquals(tc,  0, j);
1325   j = check_login_date("rainer", 1, 0);
1326   CuAssertIntEquals(tc, -1, j);
1327   j = check_login_date("rainer", 1, 6);
1328   CuAssertIntEquals(tc, -1, j);
1329   j = sh_login_set_user_allow("rainer :saturday( 0:0-23:59)");
1330   CuAssertIntEquals(tc, 0, j);
1331   j = check_login_date("rainer", 1, 6);
1332   CuAssertIntEquals(tc,  0, j);
1333   j = sh_login_set_user_allow("mouse :sunday( 0:0-23:59)");
1334   CuAssertIntEquals(tc, 0, j);
1335   j = sh_login_set_user_allow("cat :saturday(0:0-23:59)");
1336   CuAssertIntEquals(tc, 0, j);
1337   j = check_login_date("rainer", 1, 6);
1338   CuAssertIntEquals(tc,  0, j);
1339   j = check_login_date("mouse", 1, 6);
1340   CuAssertIntEquals(tc, -1, j);
1341   j = check_login_date("mouse", 1, 0);
1342   CuAssertIntEquals(tc,  0, j);
1343   j = check_login_date("cat", 1, 6);
1344   CuAssertIntEquals(tc,  0, j);
1345   j = check_login_date("dog", 1, 6);
1346   CuAssertIntEquals(tc, -1, j);
1347 
1348   sh_login_reset();
1349 
1350   /* statistics, critical values */
1351   {
1352     double f;
1353 
1354     f = M_crit(1, SIG05);
1355     CuAssertTrue(tc, f > 0.974 && f < 0.976);
1356     f = M_crit(13, SIG05);
1357     CuAssertTrue(tc, f > 0.576 && f < 0.578);
1358     f = M_crit(22, SIG05);
1359     CuAssertTrue(tc, f > 0.405 && f < 0.407);
1360     f = M_crit(10, SIG05);
1361     CuAssertTrue(tc, f > 0.646 && f < 0.648);
1362     f = M_crit(10, SIG01);
1363     CuAssertTrue(tc, f > 0.759 && f < 0.761);
1364   }
1365 
1366   /* stripped hostname */
1367   p = stripped_hostname("127.20.120.100");
1368   CuAssertStrEquals(tc, "127.20", p);
1369 
1370   p = stripped_hostname("foo.www.example.com");
1371   CuAssertStrEquals(tc, p, "www.example.com");
1372 
1373   p = stripped_hostname("www.example.com");
1374   CuAssertStrEquals(tc, p, "example.com");
1375 
1376   p = stripped_hostname("localhost");
1377   CuAssertStrEquals(tc, p, "localhost");
1378 
1379   {
1380     struct tm tt;
1381 
1382     tt.tm_hour =  0;
1383     tt.tm_min  = 30;
1384     tt.tm_sec  =  0;
1385 
1386     for (i = 0; i < 24; ++i)
1387       {
1388 	tt.tm_hour =  i;
1389 	j = time_to_index(&tt, SH_LTRACK_HTRES);
1390 	CuAssertIntEquals(tc, j, i);
1391       }
1392 
1393     tt.tm_min  = 10;
1394 
1395     for (i = 0; i < 24; ++i)
1396       {
1397 	tt.tm_hour =  i;
1398 	j = time_to_index(&tt, SH_LTRACK_GTRES);
1399 	CuAssertIntEquals(tc, 1+i*6, j);
1400       }
1401   }
1402 }
1403 /* #ifdef SH_CUTEST */
1404 #endif
1405 
1406 #else
1407 
1408 #ifdef SH_CUTEST
1409 #include <stdlib.h>
1410 #include <sys/types.h>
1411 #include <unistd.h>
1412 
1413 #include "CuTest.h"
1414 
Test_login(CuTest * tc)1415 void Test_login (CuTest *tc) {
1416   (void) tc;
1417 }
1418 
1419 /* #ifdef SH_CUTEST */
1420 #endif
1421 
1422 #endif
1423