source: trunk/src/sh_login_track.c@ 297

Last change on this file since 297 was 295, checked in by katerina, 14 years ago

Support for IPv6 (ticket #222).

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