source: trunk/src/sh_login_track.c@ 287

Last change on this file since 287 was 279, checked in by katerina, 14 years ago

Fix for tickets #200 to #206 (kernel check, login checks, bugfixes).

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