Branch data Line data Source code
1 : : // $Id: File.cc 6942 2009-11-16 03:54:08Z vern $
2 : : //
3 : : // See the file "COPYING" in the main distribution directory for copyright.
4 : :
5 : : #include "config.h"
6 : :
7 : : #include <sys/types.h>
8 : : #ifdef TIME_WITH_SYS_TIME
9 : : # include <sys/time.h>
10 : : # include <time.h>
11 : : #else
12 : : # ifdef HAVE_SYS_TIME_H
13 : : # include <sys/time.h>
14 : : # else
15 : : # include <time.h>
16 : : # endif
17 : : #endif
18 : : #include <sys/resource.h>
19 : : #include <sys/stat.h>
20 : : #include <errno.h>
21 : : #include <unistd.h>
22 : :
23 : : #include "File.h"
24 : : #include "Type.h"
25 : : #include "Timer.h"
26 : : #include "Expr.h"
27 : : #include "NetVar.h"
28 : : #include "Net.h"
29 : : #include "Serializer.h"
30 : : #include "Event.h"
31 : :
32 : : // Timer which on dispatching rotates the file.
33 : : class RotateTimer : public Timer {
34 : : public:
35 : 0 : RotateTimer(double t, BroFile* f, bool arg_raise) : Timer(t, TIMER_ROTATE)
36 : 0 : { file = f; raise = arg_raise; name = copy_string(f->Name()); }
37 : : ~RotateTimer();
38 : :
39 : : void Dispatch(double t, int is_expire);
40 : :
41 : : protected:
42 : : BroFile* file;
43 : : bool raise;
44 : : const char* name;
45 : : };
46 : :
47 : 0 : RotateTimer::~RotateTimer()
48 : : {
49 [ # # ][ # # ]: 0 : if ( file->rotate_timer == this )
[ # # ]
50 : 0 : file->rotate_timer = 0;
51 : :
52 [ # # ][ # # ]: 0 : delete [] name;
[ # # ]
53 [ # # ][ # # ]: 0 : }
[ # # ]
54 : :
55 : 0 : void RotateTimer::Dispatch(double t, int is_expire)
56 : : {
57 : 0 : file->rotate_timer = 0;
58 : :
59 [ # # ]: 0 : if ( ! is_expire )
60 : : {
61 [ # # ]: 0 : if ( raise )
62 : : {
63 : 0 : val_list* vl = new val_list;
64 : 0 : Ref(file);
65 : 0 : vl->append(new Val(file));
66 : 0 : mgr.QueueEvent(rotate_interval, vl);
67 : : }
68 : :
69 : 0 : file->InstallRotateTimer();
70 : : }
71 : 0 : }
72 : :
73 : :
74 : : // The following could in principle be part of a "file manager" object.
75 : :
76 : : #define MAX_FILE_CACHE_SIZE 32
77 : : static int num_files_in_cache = 0;
78 : : static int max_files_in_cache = 0;
79 : : static BroFile* head = 0;
80 : : static BroFile* tail = 0;
81 : :
82 : : double BroFile::default_rotation_interval = 0;
83 : : double BroFile::default_rotation_size = 0;
84 : :
85 : : // Maximizes the number of open file descriptors and returns the number
86 : : // that we should use for the cache.
87 : 2 : static int maximize_num_fds()
88 : : {
89 : : #ifdef NO_HAVE_SETRLIMIT
90 : : return MAX_FILE_CACHE_SIZE;
91 : : #else
92 : : struct rlimit rl;
93 [ - + ]: 2 : if ( getrlimit(RLIMIT_NOFILE, &rl) < 0 )
94 : 0 : internal_error("maximize_num_fds(): getrlimit failed");
95 : :
96 [ + - ]: 2 : if ( rl.rlim_max == RLIM_INFINITY )
97 : : {
98 : : // Don't try raising the current limit.
99 [ - + ]: 2 : if ( rl.rlim_cur == RLIM_INFINITY )
100 : : // Let's not be too ambitious.
101 : 0 : return MAX_FILE_CACHE_SIZE;
102 : : else
103 : 2 : return rl.rlim_cur / 2;
104 : : }
105 : :
106 : : // See if we can raise the current to the maximum.
107 : 0 : rl.rlim_cur = rl.rlim_max;
108 : :
109 [ # # ]: 0 : if ( setrlimit(RLIMIT_NOFILE, &rl) < 0 )
110 : 0 : internal_error("maximize_num_fds(): setrlimit failed");
111 : :
112 : 2 : return rl.rlim_cur / 2;
113 : : #endif
114 : : }
115 : :
116 : :
117 : 2 : BroFile::BroFile(FILE* arg_f)
118 : : {
119 : 2 : Init();
120 : 2 : f = arg_f;
121 : 2 : name = access = 0;
122 : 2 : t = base_type(TYPE_STRING);
123 : 2 : is_open = (f != 0);
124 : :
125 [ + - # # ]: 2 : if ( f )
126 : 2 : UpdateFileSize();
127 : 2 : }
128 : :
129 : 0 : BroFile::BroFile(FILE* arg_f, const char* arg_name, const char* arg_access)
130 : : {
131 : 0 : Init();
132 : 0 : f = arg_f;
133 : 0 : name = copy_string(arg_name);
134 : 0 : access = copy_string(arg_access);
135 : 0 : t = base_type(TYPE_STRING);
136 : 0 : is_open = (f != 0);
137 : :
138 [ # # # # ]: 0 : if ( f )
139 : 0 : UpdateFileSize();
140 : 0 : }
141 : :
142 : 49 : BroFile::BroFile(const char* arg_name, const char* arg_access, BroType* arg_t)
143 : : {
144 : 49 : Init();
145 : :
146 : 49 : name = copy_string(arg_name);
147 : 49 : access = copy_string(arg_access);
148 [ + - ][ # # ]: 49 : t = arg_t ? arg_t : base_type(TYPE_STRING);
149 [ - + ][ # # ]: 49 : if ( ! Open() )
150 : : {
151 : 0 : error(fmt("cannot open %s: %s", name, strerror(errno)));
152 : 0 : is_open = 0;
153 : 0 : okay_to_manage = 0;
154 : : }
155 : 49 : }
156 : :
157 : 5 : const char* BroFile::Name() const
158 : : {
159 [ + - ]: 5 : if ( name )
160 : 5 : return name;
161 : :
162 [ # # ]: 0 : if ( f == stdin )
163 : 0 : return"/dev/stdin";
164 : :
165 [ # # ]: 0 : if ( f == stdout )
166 : 0 : return "/dev/stdout";
167 : :
168 [ # # ]: 0 : if ( f == stderr )
169 : 0 : return "/dev/stderr";
170 : :
171 : 5 : return 0;
172 : : }
173 : :
174 : 49 : bool BroFile::Open(FILE* file)
175 : : {
176 [ + - ]: 49 : open_time = network_time ? network_time : current_time();
177 : :
178 [ + + ]: 49 : if ( ! max_files_in_cache )
179 : : // Haven't initialized yet.
180 : 2 : max_files_in_cache = maximize_num_fds();
181 : :
182 [ - + ]: 49 : if ( num_files_in_cache >= max_files_in_cache )
183 : 0 : PurgeCache();
184 : :
185 : 49 : f = file;
186 : :
187 [ - + ][ # # ]: 49 : if ( default_rotation_interval &&
[ # # ][ - + ]
188 : : (! attrs || ! attrs->FindAttr(ATTR_ROTATE_INTERVAL)) )
189 : 0 : rotate_interval = default_rotation_interval;
190 : :
191 [ - + ][ # # ]: 49 : if ( default_rotation_size &&
[ # # ][ - + ]
192 : : (! attrs || ! attrs->FindAttr(ATTR_ROTATE_SIZE)) )
193 : 0 : rotate_size = default_rotation_size;
194 : :
195 : 49 : InstallRotateTimer();
196 : :
197 [ + - ]: 49 : if ( ! f )
198 : : {
199 : 49 : f = fopen(name, access);
200 : 49 : SetBuf(buffered);
201 : : }
202 : :
203 [ + - ]: 49 : if ( f )
204 : : {
205 : : // These are the only files we manage, because we open them
206 : : // ourselves and hence don't have any surprises regarding
207 : : // whether we're allowed to close them.
208 : 49 : is_open = okay_to_manage = 1;
209 : :
210 : 49 : InsertAtBeginning();
211 : 49 : UpdateFileSize();
212 : : }
213 : : else
214 : : {
215 : : // No point managing it.
216 : 0 : is_open = okay_to_manage = 0;
217 : 49 : return false;
218 : : }
219 : :
220 : 49 : RaiseOpenEvent();
221 : :
222 : 49 : return true;
223 : : }
224 : :
225 : 1 : BroFile::~BroFile()
226 : : {
227 : 1 : Close();
228 : 1 : Unref(t);
229 : 1 : Unref(attrs);
230 : :
231 [ - + # # ]: 1 : delete [] name;
[ # # ]
232 [ - + ][ # # ]: 1 : delete [] access;
[ # # ]
233 [ - + ][ # # ]: 1 : delete [] cipher_buffer;
[ # # ]
234 : :
235 : : #ifdef USE_PERFTOOLS
236 : : heap_checker->UnIgnoreObject(this);
237 : : #endif
238 [ + - ][ # # ]: 1 : }
[ # # ]
239 : :
240 : 51 : void BroFile::Init()
241 : : {
242 : 51 : is_open = okay_to_manage = is_in_cache = 0;
243 : 51 : position = 0;
244 : 51 : next = prev = 0;
245 : 51 : rotate_timer = 0;
246 : 51 : rotate_interval = 0.0;
247 : 51 : rotate_size = current_size = 0.0;
248 : 51 : open_time = 0;
249 : 51 : attrs = 0;
250 : 51 : buffered = true;
251 : 51 : print_hook = true;
252 : 51 : raw_output = false;
253 : 51 : t = 0;
254 : 51 : pub_key = 0;
255 : 51 : cipher_ctx = 0;
256 : 51 : cipher_buffer = 0;
257 : :
258 : : #ifdef USE_PERFTOOLS
259 : : heap_checker->IgnoreObject(this);
260 : : #endif
261 : 51 : }
262 : :
263 : 0 : FILE* BroFile::File()
264 : : {
265 [ # # ][ # # ]: 0 : if ( okay_to_manage && ! is_in_cache )
266 : 0 : f = BringIntoCache();
267 : :
268 : 0 : return f;
269 : : }
270 : :
271 : 0 : FILE* BroFile::BringIntoCache()
272 : : {
273 [ # # ]: 0 : if ( f )
274 : 0 : internal_error("BroFile non-nil non-open file");
275 : :
276 [ # # ]: 0 : if ( num_files_in_cache >= max_files_in_cache )
277 : 0 : PurgeCache();
278 : :
279 [ # # ]: 0 : if ( position == 0 )
280 : : // Need to truncate it.
281 : 0 : f = fopen(name, access);
282 : : else
283 : : // Don't clobber it.
284 : 0 : f = fopen(name, "a");
285 : :
286 [ # # ]: 0 : if ( ! f )
287 : : {
288 : 0 : run_time("can't open %s", this);
289 : :
290 : 0 : f = fopen("/dev/null", "w");
291 : :
292 [ # # ]: 0 : if ( ! f )
293 : 0 : internal_error("out of file descriptors");
294 : :
295 : 0 : okay_to_manage = 0;
296 : 0 : return f;
297 : : }
298 : :
299 : 0 : RaiseOpenEvent();
300 : 0 : UpdateFileSize();
301 : :
302 [ # # ]: 0 : if ( fseek(f, position, SEEK_SET) < 0 )
303 : 0 : run_time("reopen seek failed", this);
304 : :
305 : 0 : InsertAtBeginning();
306 : :
307 : 0 : return f;
308 : : }
309 : :
310 : 0 : FILE* BroFile::Seek(long new_position)
311 : : {
312 [ # # ]: 0 : if ( ! File() )
313 : 0 : return 0;
314 : :
315 [ # # ]: 0 : if ( fseek(f, new_position, SEEK_SET) < 0 )
316 : 0 : run_time("seek failed", this);
317 : :
318 : 0 : return f;
319 : : }
320 : :
321 : 49 : void BroFile::SetBuf(bool arg_buffered)
322 : : {
323 [ - + ]: 49 : if ( ! f )
324 : 0 : return;
325 : :
326 [ + - ][ - + ]: 49 : if ( setvbuf(f, NULL, arg_buffered ? _IOFBF : _IOLBF, 0) != 0 )
327 : 0 : run_time("setvbuf failed", this);
328 : :
329 : 49 : buffered = arg_buffered;
330 : : }
331 : :
332 : 9 : int BroFile::Close()
333 : : {
334 [ - + ]: 9 : if ( rotate_timer )
335 : : {
336 : 0 : timer_mgr->Cancel(rotate_timer);
337 : 0 : rotate_timer = 0;
338 : : }
339 : :
340 [ - + ]: 9 : if ( ! is_open )
341 : 0 : return 1;
342 : :
343 : 9 : FinishEncrypt();
344 : :
345 : : // Do not close stdout/stderr.
346 [ + - + + ]: 9 : if ( f == stdout || f == stderr )
347 : 1 : return 0;
348 : :
349 [ + - ]: 8 : if ( is_in_cache )
350 : : {
351 : 8 : Unlink();
352 [ + - ]: 8 : if ( f )
353 : : {
354 : 8 : fclose(f);
355 : 8 : f = 0;
356 : 8 : open_time = 0;
357 : : }
358 : :
359 : 8 : is_open = 0;
360 : 8 : okay_to_manage = 0; // no longer managed since will never reopen
361 : :
362 : 8 : return 1;
363 : : }
364 : :
365 : : // Not managed.
366 [ # # ]: 0 : if ( ! f )
367 : 0 : return 0;
368 : :
369 : 0 : fclose(f);
370 : 0 : f = 0;
371 : :
372 : 9 : return 1;
373 : : }
374 : :
375 : 0 : void BroFile::Suspend()
376 : : {
377 [ # # ]: 0 : if ( ! is_in_cache )
378 : 0 : internal_error("BroFile::Suspend() called for non-cached file");
379 [ # # ]: 0 : if ( ! is_open )
380 : 0 : internal_error("BroFile::Suspend() called for non-open file");
381 : :
382 : 0 : Unlink();
383 : :
384 [ # # ]: 0 : if ( ! f )
385 : 0 : internal_error("BroFile::Suspend() called for nil file");
386 : :
387 [ # # ]: 0 : if ( (position = ftell(f)) < 0 )
388 : : {
389 : 0 : run_time("ftell failed", this);
390 : 0 : position = 0;
391 : : }
392 : :
393 : 0 : fclose(f);
394 : 0 : f = 0;
395 : 0 : }
396 : :
397 : 0 : void BroFile::PurgeCache()
398 : : {
399 [ # # ]: 0 : if ( ! tail )
400 : 0 : internal_error("BroFile purge of empty cache");
401 : :
402 : 0 : tail->Suspend();
403 : 0 : }
404 : :
405 : 8 : void BroFile::Unlink()
406 : : {
407 [ + - ]: 8 : if ( is_in_cache )
408 : : {
409 [ + + ]: 8 : if ( head == this )
410 : 7 : head = Next();
411 : : else
412 : 1 : Prev()->SetNext(next);
413 : :
414 [ + + ]: 8 : if ( tail == this )
415 : 1 : tail = Prev();
416 : : else
417 : 7 : Next()->SetPrev(prev);
418 : :
419 [ + + ][ - + ]: 8 : if ( (head || tail) && ! (head && tail) )
[ + - ][ - + ]
420 : 0 : internal_error("BroFile link list botch");
421 : :
422 : 8 : is_in_cache = 0;
423 : 8 : prev = next = 0;
424 : :
425 [ - + ]: 8 : if ( --num_files_in_cache < 0 )
426 : 0 : internal_error("BroFile underflow of file cache");
427 : : }
428 : 8 : }
429 : :
430 : 49 : void BroFile::InsertAtBeginning()
431 : : {
432 [ + + ]: 49 : if ( ! head )
433 : : {
434 : 2 : head = tail = this;
435 : 2 : next = prev = 0;
436 : : }
437 : : else
438 : : {
439 : 47 : SetNext(head);
440 : 47 : SetPrev(0);
441 : 47 : head->SetPrev(this);
442 : 47 : head = this;
443 : : }
444 : :
445 [ - + ]: 49 : if ( ++num_files_in_cache > max_files_in_cache )
446 : 0 : internal_error("BroFile overflow of file cache");
447 : :
448 : 49 : is_in_cache = 1;
449 : 49 : }
450 : :
451 : 0 : void BroFile::MoveToBeginning()
452 : : {
453 [ # # ]: 0 : if ( head == this )
454 : 0 : return; // already at the beginning
455 : :
456 [ # # ][ # # ]: 0 : if ( ! is_in_cache || ! prev )
457 : 0 : internal_error("BroFile inconsistency in MoveToBeginning()");
458 : :
459 : 0 : Unlink();
460 : 0 : InsertAtBeginning();
461 : : }
462 : :
463 : 0 : void BroFile::Describe(ODesc* d) const
464 : : {
465 : 0 : d->AddSP("file");
466 : :
467 [ # # ]: 0 : if ( name )
468 : : {
469 : 0 : d->Add("\"");
470 : 0 : d->Add(name);
471 : 0 : d->AddSP("\"");
472 : : }
473 : :
474 : 0 : d->AddSP("of");
475 [ # # ]: 0 : if ( t )
476 : 0 : t->Describe(d);
477 : : else
478 : 0 : d->Add("(no type)");
479 : 0 : }
480 : :
481 : 38 : void BroFile::SetAttrs(Attributes* arg_attrs)
482 : : {
483 [ - + ]: 38 : if ( ! arg_attrs )
484 : 0 : return;
485 : :
486 : 38 : attrs = arg_attrs;
487 : 38 : Ref(attrs);
488 : :
489 : 38 : Attr* ef = attrs->FindAttr(ATTR_ROTATE_INTERVAL);
490 [ - + ]: 38 : if ( ef )
491 : 0 : rotate_interval = ef->AttrExpr()->ExprVal()->AsInterval();
492 : :
493 : 38 : ef = attrs->FindAttr(ATTR_ROTATE_SIZE);
494 [ - + ]: 38 : if ( ef )
495 : 0 : rotate_size = ef->AttrExpr()->ExprVal()->AsDouble();
496 : :
497 : 38 : ef = attrs->FindAttr(ATTR_ENCRYPT);
498 [ - + ]: 38 : if ( ef )
499 : : {
500 [ # # ]: 0 : if ( ef->AttrExpr() )
501 : 0 : InitEncrypt(ef->AttrExpr()->ExprVal()->AsString()->CheckString());
502 : : else
503 : 0 : InitEncrypt(log_encryption_key->AsString()->CheckString());
504 : : }
505 : :
506 [ - + ]: 38 : if ( attrs->FindAttr(ATTR_DISABLE_PRINT_HOOK) )
507 : 0 : DisablePrintHook();
508 : :
509 [ - + ]: 38 : if ( attrs->FindAttr(ATTR_RAW_OUTPUT) )
510 : 0 : EnableRawOutput();
511 : :
512 : 38 : InstallRotateTimer();
513 : : }
514 : :
515 : 0 : void BroFile::SetRotateInterval(double secs)
516 : : {
517 : 0 : rotate_interval = secs;
518 : 0 : InstallRotateTimer();
519 : 0 : }
520 : :
521 : 0 : RecordVal* BroFile::Rotate()
522 : : {
523 [ # # ]: 0 : if ( ! is_open )
524 : 0 : return 0;
525 : :
526 [ # # ][ # # ]: 0 : if ( okay_to_manage && ! is_in_cache )
527 : 0 : BringIntoCache();
528 : :
529 : 0 : RecordVal* info = new RecordVal(rotate_info);
530 : 0 : FILE* newf = rotate_file(name, info);
531 : :
532 [ # # ]: 0 : if ( ! newf )
533 : : {
534 : 0 : Unref(info);
535 : 0 : return 0;
536 : : }
537 : :
538 : 0 : info->Assign(2, new Val(open_time, TYPE_TIME));
539 : :
540 : 0 : Unlink();
541 : 0 : fclose(f);
542 : 0 : f = 0;
543 : :
544 : 0 : Open(newf);
545 : 0 : return info;
546 : : }
547 : :
548 : 95 : void BroFile::InstallRotateTimer()
549 : : {
550 [ - + ]: 95 : if ( terminating )
551 : 0 : return;
552 : :
553 [ - + ]: 95 : if ( rotate_timer )
554 : : {
555 : 0 : timer_mgr->Cancel(rotate_timer);
556 : 0 : rotate_timer = 0;
557 : : }
558 : :
559 [ - + ]: 95 : if ( rotate_interval )
560 : : {
561 : : // When this is called for the first time, network_time can
562 : : // still be zero. If so, we set a timer which fires
563 : : // immediately but doesn't rotate when it expires.
564 : :
565 [ # # ]: 0 : if ( ! network_time )
566 : 0 : rotate_timer = new RotateTimer(1, this, false);
567 : : else
568 : : {
569 [ # # ]: 0 : if ( ! open_time )
570 : 0 : open_time = network_time;
571 : :
572 : : const char* base_time = log_rotate_base_time ?
573 [ # # ]: 0 : log_rotate_base_time->AsString()->CheckString() : 0;
574 : :
575 : : double delta_t =
576 : 0 : calc_next_rotate(rotate_interval, base_time);
577 : : rotate_timer = new RotateTimer(network_time + delta_t,
578 : 0 : this, true);
579 : : }
580 : :
581 : 95 : timer_mgr->Add(rotate_timer);
582 : : }
583 : : }
584 : :
585 : 1 : void BroFile::SetDefaultRotation(double interval, double max_size)
586 : : {
587 [ + + ]: 9 : for ( BroFile* f = head; f; f = f->next )
588 : : {
589 [ + + ][ + - ]: 8 : if ( ! (f->attrs && f->attrs->FindAttr(ATTR_ROTATE_INTERVAL)) )
[ + - ]
590 : : {
591 : 8 : f->rotate_interval = interval;
592 : 8 : f->InstallRotateTimer();
593 : : }
594 : :
595 [ + + ][ + - ]: 8 : if ( ! (f->attrs && f->attrs->FindAttr(ATTR_ROTATE_SIZE)) )
[ + - ]
596 : 8 : f->rotate_size = max_size;
597 : : }
598 : :
599 : 1 : default_rotation_interval = interval;
600 : 1 : default_rotation_size = max_size;
601 : 1 : }
602 : :
603 : 1 : void BroFile::CloseCachedFiles()
604 : : {
605 : : BroFile* next;
606 [ + + ]: 8 : for ( BroFile* f = head; f; f = next )
607 : : {
608 : : // Send final rotate events (immediately).
609 [ - + ]: 7 : if ( f->rotate_interval )
610 : : {
611 : 0 : val_list* vl = new val_list;
612 : 0 : Ref(f);
613 : 0 : vl->append(new Val(f));
614 : 0 : Event* event = new Event(::rotate_interval, vl);
615 : 0 : mgr.Dispatch(event, true);
616 : : }
617 : :
618 [ - + ]: 7 : if ( f->rotate_size )
619 : : {
620 : 0 : val_list* vl = new val_list;
621 : 0 : Ref(f);
622 : 0 : vl->append(new Val(f));
623 : 0 : Event* event = new ::Event(::rotate_size, vl);
624 : 0 : mgr.Dispatch(event, true);
625 : : }
626 : :
627 : 7 : next = f->next;
628 [ + - ]: 7 : if ( f->is_in_cache )
629 : 7 : f->Close();
630 : : }
631 : 1 : }
632 : :
633 : 0 : void BroFile::InitEncrypt(const char* keyfile)
634 : : {
635 [ # # # # ]: 0 : if ( ! (pub_key || keyfile) )
636 : 0 : return;
637 : :
638 [ # # ]: 0 : if ( ! pub_key )
639 : : {
640 : 0 : FILE* key = fopen(keyfile, "r");
641 : :
642 [ # # ]: 0 : if ( ! key )
643 : : {
644 : 0 : error(fmt("can't open key file %s: %s", keyfile, strerror(errno)));
645 : 0 : Close();
646 : : return;
647 : : }
648 : :
649 : 0 : pub_key = PEM_read_PUBKEY(key, 0, 0, 0);
650 [ # # ]: 0 : if ( ! pub_key )
651 : : {
652 : : error(fmt("can't read key from %s: %s", keyfile,
653 : 0 : ERR_error_string(ERR_get_error(), 0)));
654 : 0 : Close();
655 : : return;
656 : : }
657 : : }
658 : :
659 : : // Depending on the OpenSSL version, EVP_*_cbc()
660 : : // returns a const or a non-const.
661 : 0 : EVP_CIPHER* cipher_type = (EVP_CIPHER*) EVP_bf_cbc();
662 : 0 : cipher_ctx = new EVP_CIPHER_CTX;
663 : :
664 : 0 : unsigned char secret[EVP_PKEY_size(pub_key)];
665 : 0 : unsigned char* psecret = secret;
666 : : unsigned long secret_len;
667 : :
668 : 0 : int iv_len = EVP_CIPHER_iv_length(cipher_type);
669 : 0 : unsigned char iv[iv_len];
670 : :
671 [ # # ]: 0 : if ( ! EVP_SealInit(cipher_ctx, cipher_type, &psecret,
672 : : (int*) &secret_len, iv, &pub_key, 1) )
673 : : {
674 : : error(fmt("can't init cipher context for %s: %s", keyfile,
675 : 0 : ERR_error_string(ERR_get_error(), 0)));
676 : 0 : Close();
677 : : return;
678 : : }
679 : :
680 : 0 : secret_len = htonl(secret_len);
681 : :
682 [ # # # # ]: 0 : if ( ! (fwrite("BROENC1", 7, 1, f) &&
[ # # ][ # # ]
[ # # ]
683 : : fwrite(&secret_len, sizeof(secret_len), 1, f) &&
684 : : fwrite(secret, ntohl(secret_len), 1, f) &&
685 : : fwrite(iv, iv_len, 1, f)) )
686 : : {
687 : : error(fmt("can't write header to log file %s: %s",
688 : 0 : name, strerror(errno)));
689 : 0 : Close();
690 : : return;
691 : : }
692 : :
693 : 0 : int buf_size = MIN_BUFFER_SIZE + EVP_CIPHER_block_size(cipher_type);
694 [ # # ]: 0 : cipher_buffer = new unsigned char[buf_size];
695 : : }
696 : :
697 : 9 : void BroFile::FinishEncrypt()
698 : : {
699 [ - + ]: 9 : if ( ! is_open )
700 : 0 : return;
701 : :
702 [ + - ]: 9 : if ( ! pub_key )
703 : 9 : return;
704 : :
705 [ # # ]: 0 : if ( cipher_ctx )
706 : : {
707 : : int outl;
708 : 0 : EVP_SealFinal(cipher_ctx, cipher_buffer, &outl);
709 : :
710 [ # # # # ]: 0 : if ( outl && ! fwrite(cipher_buffer, outl, 1, f) )
[ # # ]
711 : : {
712 : : run_time(fmt("write error for %s: %s",
713 : 0 : name, strerror(errno)));
714 : 0 : return;
715 : : }
716 : :
717 : 0 : delete cipher_ctx;
718 : 9 : cipher_ctx = 0;
719 : : }
720 : : }
721 : :
722 : :
723 : 11309 : int BroFile::Write(const char* data, int len)
724 : : {
725 [ - + ]: 11309 : if ( ! is_open )
726 : 0 : return 0;
727 : :
728 [ + + ][ - + ]: 11309 : if ( ! is_in_cache && okay_to_manage )
729 : 0 : BringIntoCache();
730 : :
731 [ + + ]: 11309 : if ( ! len )
732 : 1379 : len = strlen(data);
733 : :
734 [ - + ]: 11309 : if ( cipher_ctx )
735 : : {
736 [ # # ]: 0 : while ( len )
737 : : {
738 : : int outl;
739 : 0 : int inl = min(MIN_BUFFER_SIZE, len);
740 : :
741 [ # # ]: 0 : if ( ! EVP_SealUpdate(cipher_ctx, cipher_buffer, &outl,
742 : : (unsigned char*)data, inl) )
743 : : {
744 : : run_time(fmt("encryption error for %s: %s",
745 : : name,
746 : 0 : ERR_error_string(ERR_get_error(), 0)));
747 : 0 : Close();
748 : 0 : return 0;
749 : : }
750 : :
751 [ # # ][ # # ]: 0 : if ( outl && ! fwrite(cipher_buffer, outl, 1, f) )
[ # # ]
752 : : {
753 : : run_time(fmt("write error for %s: %s",
754 : 0 : name, strerror(errno)));
755 : 0 : Close();
756 : 0 : return 0;
757 : : }
758 : :
759 : 0 : data += inl;
760 : 0 : len -= inl;
761 : : }
762 : :
763 : 0 : return 1;
764 : : }
765 : :
766 : 11309 : len = fwrite(data, 1, len, f);
767 [ - + ]: 11309 : if ( len <= 0 )
768 : 0 : return false;
769 : :
770 [ - + ][ # # ]: 11309 : if ( rotate_size && current_size < rotate_size && current_size + len >= rotate_size )
[ # # ]
771 : : {
772 : 0 : val_list* vl = new val_list;
773 : 0 : vl->append(new Val(this));
774 : 0 : mgr.QueueEvent(::rotate_size, vl);
775 : : }
776 : :
777 : : // This does not work if we seek around. But none of the logs does that
778 : : // and we avoid stat()'ing the file all the time.
779 : 11309 : current_size += len;
780 : :
781 : 11309 : return true;
782 : : }
783 : :
784 : 49 : void BroFile::RaiseOpenEvent()
785 : : {
786 [ + + ]: 49 : if ( ! ::file_opened )
787 : 49 : return;
788 : :
789 : 5 : val_list* vl = new val_list;
790 : 5 : Ref(this);
791 : 5 : vl->append(new Val(this));
792 : 5 : Event* event = new ::Event(::file_opened, vl);
793 : 5 : mgr.Dispatch(event, true);
794 : : }
795 : :
796 : 51 : void BroFile::UpdateFileSize()
797 : : {
798 : : struct stat s;
799 [ - + ]: 51 : if ( fstat(fileno(f), &s) < 0 )
800 : : {
801 : 0 : run_time(fmt("can't stat fd for %s: %s", name, strerror(errno)));
802 : 0 : current_size = 0;
803 : 0 : return;
804 : : }
805 : :
806 : 51 : current_size = double(s.st_size);
807 : : }
808 : :
809 : 0 : bool BroFile::Serialize(SerialInfo* info) const
810 : : {
811 : 0 : return SerialObj::Serialize(info);
812 : : }
813 : :
814 : 0 : BroFile* BroFile::GetFile(const char* name)
815 : : {
816 [ # # ]: 0 : for ( BroFile* f = head; f; f = f->next )
817 : : {
818 [ # # ][ # # ]: 0 : if ( f->name && streq(name, f->name) )
[ # # ]
819 : 0 : return f;
820 : : }
821 : :
822 : 0 : return new BroFile(name, "w", 0);
823 : : }
824 : :
825 : 0 : BroFile* BroFile::Unserialize(UnserialInfo* info)
826 : : {
827 : 0 : BroFile* file = (BroFile*) SerialObj::Unserialize(info, SER_BRO_FILE);
828 : :
829 [ # # ]: 0 : if ( ! file )
830 : 0 : return 0;
831 : :
832 [ # # ]: 0 : if ( file->is_open )
833 : 0 : return file;
834 : :
835 : : // If there is already an object for this file, return it.
836 [ # # ]: 0 : if ( file->name )
837 : : {
838 [ # # ]: 0 : for ( BroFile* f = head; f; f = f->next )
839 : : {
840 [ # # ][ # # ]: 0 : if ( f->name && streq(file->name, f->name) )
[ # # ]
841 : : {
842 : 0 : Unref(file);
843 : 0 : Ref(f);
844 : 0 : return f;
845 : : }
846 : : }
847 : : }
848 : :
849 : : // Otherwise, open.
850 [ # # ]: 0 : if ( ! file->Open() )
851 : : {
852 : : info->s->Error(fmt("cannot open %s: %s",
853 : 0 : file->name, strerror(errno)));
854 : 0 : return 0;
855 : : }
856 : :
857 : : // Here comes a hack. This method will return a pointer to a newly
858 : : // instantiated file object. As soon as this pointer is Unref'ed, the
859 : : // file will be closed. That means that when we unserialize the same
860 : : // file next time, we will re-open it and thereby delete the first one,
861 : : // i.e., we will be keeping to delete what we've written just before.
862 : : //
863 : : // To avoid this loop, we do an extra Ref here, i.e., this file will
864 : : // *never* be closed anymore (as long the file cache does not overflow).
865 : 0 : Ref(file);
866 : :
867 : : // We deliberately override log rotation attributes with our defaults.
868 : 0 : file->rotate_interval = log_rotate_interval;
869 : 0 : file->rotate_size = log_max_size;
870 : 0 : file->InstallRotateTimer();
871 : 0 : file->SetBuf(file->buffered);
872 : :
873 : 0 : return file;
874 : : }
875 : :
876 : 3 : IMPLEMENT_SERIAL(BroFile, SER_BRO_FILE);
877 : :
878 : 0 : bool BroFile::DoSerialize(SerialInfo* info) const
879 : : {
880 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_BRO_FILE, BroObj);
881 : :
882 : 0 : const char* s = name;
883 : :
884 [ # # ]: 0 : if ( ! okay_to_manage )
885 : : {
886 : : // We can handle stdin/stdout/stderr but no others.
887 [ # # ]: 0 : if ( f == stdin )
888 : 0 : s = "/dev/stdin";
889 [ # # ]: 0 : else if ( f == stdout )
890 : 0 : s = "/dev/stdout";
891 [ # # ]: 0 : else if ( f == stderr )
892 : 0 : s = "/dev/stderr";
893 : : else
894 : : {
895 : : // We don't manage the file, and therefore don't
896 : : // really know how to pass it on to the other side.
897 : : // However, in order to not abort communication
898 : : // when this happens, we still send the name if we
899 : : // have one; or if we don't, we create a special
900 : : // "dont-have-a-file" file to be created on the
901 : : // receiver side.
902 [ # # ]: 0 : if ( ! s )
903 : 0 : s = "unmanaged-bro-output-file.log";
904 : : }
905 : : }
906 : :
907 [ # # ][ # # ]: 0 : if ( ! (SERIALIZE(s) && SERIALIZE(buffered)) )
[ # # ]
908 : 0 : return false;
909 : :
910 [ # # ][ # # ]: 0 : SERIALIZE_OPTIONAL_STR(access);
[ # # ][ # # ]
[ # # ]
911 : :
912 [ # # ]: 0 : if ( ! t->Serialize(info) )
913 : 0 : return false;
914 : :
915 [ # # ][ # # ]: 0 : SERIALIZE_OPTIONAL(attrs);
[ # # ][ # # ]
[ # # ][ # # ]
916 : 0 : return true;
917 : : }
918 : :
919 : 0 : bool BroFile::DoUnserialize(UnserialInfo* info)
920 : : {
921 [ # # ]: 0 : DO_UNSERIALIZE(BroObj);
922 : :
923 [ # # ][ # # ]: 0 : if ( ! (UNSERIALIZE_STR(&name, 0) && UNSERIALIZE(&buffered)) )
[ # # ]
924 : 0 : return false;
925 : :
926 [ # # ][ # # ]: 0 : UNSERIALIZE_OPTIONAL_STR(access);
[ # # ]
927 : :
928 : 0 : t = BroType::Unserialize(info);
929 [ # # ]: 0 : if ( ! t )
930 : 0 : return false;
931 : :
932 [ # # ][ # # ]: 0 : UNSERIALIZE_OPTIONAL(attrs, Attributes::Unserialize(info));
[ # # ]
933 : :
934 : : // Parse attributes.
935 : 0 : SetAttrs(attrs);
936 : : // SetAttrs() has ref'ed attrs again.
937 : 0 : Unref(attrs);
938 : :
939 : : // Bind stdin/stdout/stderr.
940 : 0 : FILE* file = 0;
941 : 0 : is_open = false;
942 : 0 : f = 0;
943 : :
944 [ # # ]: 0 : if ( streq(name, "/dev/stdin") )
945 : 0 : file = stdin;
946 [ # # ]: 0 : else if ( streq(name, "/dev/stdout") )
947 : 0 : file = stdout;
948 [ # # ]: 0 : else if ( streq(name, "/dev/stderr") )
949 : 0 : file = stderr;
950 : :
951 [ # # ]: 0 : if ( file )
952 : : {
953 [ # # ]: 0 : delete [] name;
954 : 0 : name = 0;
955 : 0 : f = file;
956 : 0 : is_open = true;
957 : : }
958 : :
959 : 0 : return true;
960 [ + - ][ + - ]: 6 : }
|