2 * Unix SMB/CIFS implementation.
3 * Eventlog utility routines
4 * Copyright (C) Marcin Krzysztof Porwit 2005,
5 * Copyright (C) Brian Moran 2005.
6 * Copyright (C) Gerald (Jerry) Carter 2005.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 /* maintain a list of open eventlog tdbs with reference counts */
27 static ELOG_TDB
*open_elog_list
;
29 /********************************************************************
30 Init an Eventlog TDB, and return it. If null, something bad
32 ********************************************************************/
34 TDB_CONTEXT
*elog_init_tdb( char *tdbfilename
)
38 DEBUG(10,("elog_init_tdb: Initializing eventlog tdb (%s)\n",
41 tdb
= tdb_open_log( tdbfilename
, 0, TDB_DEFAULT
,
42 O_RDWR
|O_CREAT
|O_TRUNC
, 0660 );
45 DEBUG( 0, ( "Can't open tdb for [%s]\n", tdbfilename
) );
49 /* initialize with defaults, copy real values in here from registry */
51 tdb_store_int32( tdb
, EVT_OLDEST_ENTRY
, 1 );
52 tdb_store_int32( tdb
, EVT_NEXT_RECORD
, 1 );
53 tdb_store_int32( tdb
, EVT_MAXSIZE
, 0x80000 );
54 tdb_store_int32( tdb
, EVT_RETENTION
, 0x93A80 );
56 tdb_store_int32( tdb
, EVT_VERSION
, EVENTLOG_DATABASE_VERSION_V1
);
61 /********************************************************************
62 make the tdb file name for an event log, given destination buffer
63 and size. Caller must free memory.
64 ********************************************************************/
66 char *elog_tdbname( const char *name
)
70 char *eventlogdir
= lock_path( "eventlog" );
72 pstr_sprintf( path
, "%s/%s.tdb", eventlogdir
, name
);
74 tdb_fullpath
= SMB_STRDUP( path
);
80 /********************************************************************
81 this function is used to count up the number of bytes in a
83 ********************************************************************/
85 struct trav_size_struct
{
90 static int eventlog_tdb_size_fn( TDB_CONTEXT
* tdb
, TDB_DATA key
, TDB_DATA data
,
93 struct trav_size_struct
*tsize
= state
;
95 tsize
->size
+= data
.dsize
;
101 /********************************************************************
102 returns the size of the eventlog, and if MaxSize is a non-null
103 ptr, puts the MaxSize there. This is purely a way not to have yet
104 another function that solely reads the maxsize of the eventlog.
106 ********************************************************************/
108 int elog_tdb_size( TDB_CONTEXT
* tdb
, int *MaxSize
, int *Retention
)
110 struct trav_size_struct tsize
;
115 ZERO_STRUCT( tsize
);
117 tdb_traverse( tdb
, eventlog_tdb_size_fn
, &tsize
);
119 if ( MaxSize
!= NULL
) {
120 *MaxSize
= tdb_fetch_int32( tdb
, EVT_MAXSIZE
);
123 if ( Retention
!= NULL
) {
124 *Retention
= tdb_fetch_int32( tdb
, EVT_RETENTION
);
128 ( "eventlog size: [%d] for [%d] records\n", tsize
.size
,
133 /********************************************************************
134 Discard early event logs until we have enough for 'needed' bytes...
135 NO checking done beforehand to see that we actually need to do
136 this, and it's going to pluck records one-by-one. So, it's best
137 to determine that this needs to be done before doing it.
139 Setting whack_by_date to True indicates that eventlogs falling
140 outside of the retention range need to go...
142 return True if we made enough room to accommodate needed bytes
143 ********************************************************************/
145 BOOL
make_way_for_eventlogs( TDB_CONTEXT
* the_tdb
, int32 needed
,
148 int start_record
, i
, new_start
;
150 int nbytes
, reclen
, len
, Retention
, MaxSize
;
151 int tresv1
, trecnum
, timegen
, timewr
;
153 TALLOC_CTX
*mem_ctx
= NULL
;
154 time_t current_time
, exp_time
;
156 /* discard some eventlogs */
158 /* read eventlogs from oldest_entry -- there can't be any discontinuity in recnos,
159 although records not necessarily guaranteed to have successive times */
161 mem_ctx
= talloc_init( "make_way_for_eventlogs" ); /* Homage to BPG */
163 if ( mem_ctx
== NULL
)
164 return False
; /* can't allocate memory indicates bigger problems */
166 tdb_lock_bystring_with_timeout( the_tdb
, EVT_NEXT_RECORD
, 1 );
168 end_record
= tdb_fetch_int32( the_tdb
, EVT_NEXT_RECORD
);
169 start_record
= tdb_fetch_int32( the_tdb
, EVT_OLDEST_ENTRY
);
170 Retention
= tdb_fetch_int32( the_tdb
, EVT_RETENTION
);
171 MaxSize
= tdb_fetch_int32( the_tdb
, EVT_MAXSIZE
);
173 time( ¤t_time
);
176 exp_time
= current_time
- Retention
; /* discard older than exp_time */
178 /* todo - check for sanity in next_record */
182 ( "MaxSize [%d] Retention [%d] Current Time [%d] exp_time [%d]\n",
183 MaxSize
, Retention
, (uint32
)current_time
, (uint32
)exp_time
) );
185 ( "Start Record [%d] End Record [%d]\n", start_record
,
188 for ( i
= start_record
; i
< end_record
; i
++ ) {
189 /* read a record, add the amt to nbytes */
190 key
.dsize
= sizeof( int32
);
191 key
.dptr
= ( char * ) ( int32
* ) & i
;
192 ret
= tdb_fetch( the_tdb
, key
);
193 if ( ret
.dsize
== 0 ) {
195 ( "Can't find a record for the key, record [%d]\n",
197 tdb_unlock_bystring( the_tdb
, EVT_NEXT_RECORD
);
200 nbytes
+= ret
.dsize
; /* note this includes overhead */
202 len
= tdb_unpack( ret
.dptr
, ret
.dsize
, "ddddd", &reclen
,
203 &tresv1
, &trecnum
, &timegen
, &timewr
);
205 DEBUG( 10,("make_way_for_eventlogs: tdb_unpack failed.\n"));
206 tdb_unlock_bystring( the_tdb
, EVT_NEXT_RECORD
);
211 ( "read record %d, record size is [%d], total so far [%d]\n",
212 i
, reclen
, nbytes
) );
214 SAFE_FREE( ret
.dptr
);
216 /* note that other servers may just stop writing records when the size limit
217 is reached, and there are no records older than 'retention'. This doesn't
218 like a very useful thing to do, so instead we whack (as in sleeps with the
219 fishes) just enough records to fit the what we need. This behavior could
220 be changed to 'match', if the need arises. */
222 if ( !whack_by_date
&& ( nbytes
>= needed
) )
224 if ( whack_by_date
&& ( timegen
>= exp_time
) )
229 ( "nbytes [%d] needed [%d] start_record is [%d], should be set to [%d]\n",
230 nbytes
, needed
, start_record
, i
) );
231 /* todo - remove eventlog entries here and set starting record to start_record... */
233 if ( start_record
!= new_start
) {
234 for ( i
= start_record
; i
< new_start
; i
++ ) {
235 key
.dsize
= sizeof( int32
);
236 key
.dptr
= ( char * ) ( int32
* ) & i
;
237 tdb_delete( the_tdb
, key
);
240 tdb_store_int32( the_tdb
, EVT_OLDEST_ENTRY
, new_start
);
242 tdb_unlock_bystring( the_tdb
, EVT_NEXT_RECORD
);
246 /********************************************************************
247 some hygiene for an eventlog - see how big it is, and then
248 calculate how many bytes we need to remove
249 ********************************************************************/
251 BOOL
prune_eventlog( TDB_CONTEXT
* tdb
)
253 int MaxSize
, Retention
, CalcdSize
;
256 DEBUG( 4, ( "No eventlog tdb handle\n" ) );
260 CalcdSize
= elog_tdb_size( tdb
, &MaxSize
, &Retention
);
262 ( "Calculated size [%d] MaxSize [%d]\n", CalcdSize
,
265 if ( CalcdSize
> MaxSize
) {
266 return make_way_for_eventlogs( tdb
, CalcdSize
- MaxSize
,
270 return make_way_for_eventlogs( tdb
, 0, True
);
273 /********************************************************************
274 ********************************************************************/
276 BOOL
can_write_to_eventlog( TDB_CONTEXT
* tdb
, int32 needed
)
279 int MaxSize
, Retention
;
281 /* see if we can write to the eventlog -- do a policy enforcement */
283 return False
; /* tdb is null, so we can't write to it */
291 calcd_size
= elog_tdb_size( tdb
, &MaxSize
, &Retention
);
293 if ( calcd_size
<= MaxSize
)
294 return True
; /* you betcha */
295 if ( calcd_size
+ needed
< MaxSize
)
298 if ( Retention
== 0xffffffff ) {
299 return False
; /* see msdn - we can't write no room, discard */
302 note don't have to test, but always good to show intent, in case changes needed
306 if ( Retention
== 0x00000000 ) {
307 /* discard record(s) */
308 /* todo - decide when to remove a bunch vs. just what we need... */
309 return make_way_for_eventlogs( tdb
, calcd_size
- MaxSize
,
313 return make_way_for_eventlogs( tdb
, calcd_size
- MaxSize
, False
);
316 /*******************************************************************
317 *******************************************************************/
319 ELOG_TDB
*elog_open_tdb( char *logname
, BOOL force_clear
)
321 TDB_CONTEXT
*tdb
= NULL
;
326 ELOG_TDB
*tdb_node
= NULL
;
329 /* first see if we have an open context */
331 for ( ptr
=open_elog_list
; ptr
; ptr
=ptr
->next
) {
332 if ( strequal( ptr
->name
, logname
) ) {
335 /* trick to alow clearing of the eventlog tdb.
336 The force_clear flag should imply that someone
337 has done a force close. So make sure the tdb
338 is NULL. If this is a normal open, then just
339 return the existing reference */
342 SMB_ASSERT( ptr
->tdb
== NULL
);
350 /* make sure that the eventlog dir exists */
352 eventlogdir
= lock_path( "eventlog" );
353 if ( !directory_exist( eventlogdir
, NULL
) )
354 mkdir( eventlogdir
, 0755 );
356 /* get the path on disk */
358 tdbfilename
= elog_tdbname( logname
);
359 pstrcpy( tdbpath
, tdbfilename
);
360 SAFE_FREE( tdbfilename
);
362 DEBUG(7,("elog_open_tdb: Opening %s...(force_clear == %s)\n",
363 tdbpath
, force_clear
?"True":"False" ));
365 /* the tdb wasn't already open or this is a forced clear open */
367 if ( !force_clear
) {
369 tdb
= tdb_open_log( tdbpath
, 0, TDB_DEFAULT
, O_RDWR
, 0 );
371 vers_id
= tdb_fetch_int32( tdb
, EVT_VERSION
);
373 if ( vers_id
!= EVENTLOG_DATABASE_VERSION_V1
) {
374 DEBUG(1,("elog_open_tdb: Invalid version [%d] on file [%s].\n",
377 tdb
= elog_init_tdb( tdbpath
);
383 tdb
= elog_init_tdb( tdbpath
);
385 /* if we got a valid context, then add it to the list */
388 /* on a forced clear, just reset the tdb context if we already
389 have an open entry in the list */
396 if ( !(tdb_node
= TALLOC_ZERO_P( NULL
, ELOG_TDB
)) ) {
397 DEBUG(0,("elog_open_tdb: talloc() failure!\n"));
402 tdb_node
->name
= talloc_strdup( tdb_node
, logname
);
404 tdb_node
->ref_count
= 1;
406 DLIST_ADD( open_elog_list
, tdb_node
);
412 /*******************************************************************
413 Wrapper to handle reference counts to the tdb
414 *******************************************************************/
416 int elog_close_tdb( ELOG_TDB
*etdb
, BOOL force_close
)
425 SMB_ASSERT( etdb
->ref_count
>= 0 );
427 if ( etdb
->ref_count
== 0 ) {
429 DLIST_REMOVE( open_elog_list
, etdb
);
431 return tdb_close( tdb
);
437 return tdb_close( tdb
);
444 /*******************************************************************
445 write an eventlog entry. Note that we have to lock, read next
446 eventlog, increment, write, write the record, unlock
448 coming into this, ee has the eventlog record, and the auxilliary date
449 (computer name, etc.) filled into the other structure. Before packing
450 into a record, this routine will calc the appropriate padding, etc.,
451 and then blast out the record in a form that can be read back in
452 *******************************************************************/
456 int write_eventlog_tdb( TDB_CONTEXT
* the_tdb
, Eventlog_entry
* ee
)
460 TALLOC_CTX
*mem_ctx
= NULL
;
467 mem_ctx
= talloc_init( "write_eventlog_tdb" );
469 if ( mem_ctx
== NULL
)
474 /* discard any entries that have bogus time, which usually indicates a bogus entry as well. */
475 if ( ee
->record
.time_generated
== 0 )
478 /* todo - check for sanity in next_record */
480 fixup_eventlog_entry( ee
);
482 if ( !can_write_to_eventlog( the_tdb
, ee
->record
.length
) ) {
483 DEBUG( 3, ( "Can't write to Eventlog, no room \n" ) );
484 talloc_destroy( mem_ctx
);
488 /* alloc mem for the packed version */
489 packed_ee
= (uint8
*)TALLOC( mem_ctx
, ee
->record
.length
+ MARGIN
);
491 talloc_destroy( mem_ctx
);
495 /* need to read the record number and insert it into the entry here */
498 tdb_lock_bystring_with_timeout( the_tdb
, EVT_NEXT_RECORD
, 1 );
500 next_record
= tdb_fetch_int32( the_tdb
, EVT_NEXT_RECORD
);
503 tdb_pack( (char *)packed_ee
, ee
->record
.length
+ MARGIN
,
504 "ddddddwwwwddddddBBdBBBd", ee
->record
.length
,
505 ee
->record
.reserved1
, next_record
,
506 ee
->record
.time_generated
, ee
->record
.time_written
,
507 ee
->record
.event_id
, ee
->record
.event_type
,
508 ee
->record
.num_strings
, ee
->record
.event_category
,
509 ee
->record
.reserved2
,
510 ee
->record
.closing_record_number
,
511 ee
->record
.string_offset
,
512 ee
->record
.user_sid_length
,
513 ee
->record
.user_sid_offset
, ee
->record
.data_length
,
514 ee
->record
.data_offset
,
515 ee
->data_record
.source_name_len
,
516 ee
->data_record
.source_name
,
517 ee
->data_record
.computer_name_len
,
518 ee
->data_record
.computer_name
,
519 ee
->data_record
.sid_padding
,
520 ee
->record
.user_sid_length
, ee
->data_record
.sid
,
521 ee
->data_record
.strings_len
,
522 ee
->data_record
.strings
,
523 ee
->data_record
.user_data_len
,
524 ee
->data_record
.user_data
,
525 ee
->data_record
.data_padding
);
527 /*DEBUG(3,("write_eventlog_tdb: packed into %d\n",n_packed)); */
529 /* increment the record count */
531 kbuf
.dsize
= sizeof( int32
);
532 kbuf
.dptr
= (char * ) & next_record
;
534 ebuf
.dsize
= n_packed
;
535 ebuf
.dptr
= (char *)packed_ee
;
537 if ( tdb_store( the_tdb
, kbuf
, ebuf
, 0 ) ) {
538 /* DEBUG(1,("write_eventlog_tdb: Can't write record %d to eventlog\n",next_record)); */
539 tdb_unlock_bystring( the_tdb
, EVT_NEXT_RECORD
);
540 talloc_destroy( mem_ctx
);
544 tdb_store_int32( the_tdb
, EVT_NEXT_RECORD
, next_record
);
545 tdb_unlock_bystring( the_tdb
, EVT_NEXT_RECORD
);
546 talloc_destroy( mem_ctx
);
547 return ( next_record
- 1 );
550 /*******************************************************************
551 calculate the correct fields etc for an eventlog entry
552 *******************************************************************/
554 void fixup_eventlog_entry( Eventlog_entry
* ee
)
556 /* fix up the eventlog entry structure as necessary */
558 ee
->data_record
.sid_padding
=
560 ( ( ee
->data_record
.source_name_len
+
561 ee
->data_record
.computer_name_len
) % 4 ) ) % 4 );
562 ee
->data_record
.data_padding
=
564 ( ( ee
->data_record
.strings_len
+
565 ee
->data_record
.user_data_len
) % 4 ) ) % 4;
566 ee
->record
.length
= sizeof( Eventlog_record
);
567 ee
->record
.length
+= ee
->data_record
.source_name_len
;
568 ee
->record
.length
+= ee
->data_record
.computer_name_len
;
569 if ( ee
->record
.user_sid_length
== 0 ) {
570 /* Should not pad to a DWORD boundary for writing out the sid if there is
571 no SID, so just propagate the padding to pad the data */
572 ee
->data_record
.data_padding
+= ee
->data_record
.sid_padding
;
573 ee
->data_record
.sid_padding
= 0;
575 /* DEBUG(10, ("sid_padding is [%d].\n", ee->data_record.sid_padding)); */
576 /* DEBUG(10, ("data_padding is [%d].\n", ee->data_record.data_padding)); */
578 ee
->record
.length
+= ee
->data_record
.sid_padding
;
579 ee
->record
.length
+= ee
->record
.user_sid_length
;
580 ee
->record
.length
+= ee
->data_record
.strings_len
;
581 ee
->record
.length
+= ee
->data_record
.user_data_len
;
582 ee
->record
.length
+= ee
->data_record
.data_padding
;
583 /* need another copy of length at the end of the data */
584 ee
->record
.length
+= sizeof( ee
->record
.length
);
587 /********************************************************************
588 Note that it's a pretty good idea to initialize the Eventlog_entry
589 structure to zero's before calling parse_logentry on an batch of
590 lines that may resolve to a record. ALSO, it's a good idea to
591 remove any linefeeds (that's EOL to you and me) on the lines
593 ********************************************************************/
595 BOOL
parse_logentry( char *line
, Eventlog_entry
* entry
, BOOL
* eor
)
597 char *start
= NULL
, *stop
= NULL
;
603 /* empty line signyfiying record delimeter, or we're at the end of the buffer */
604 if ( start
== NULL
|| strlen( start
) == 0 ) {
606 ( "parse_logentry: found end-of-record indicator.\n" ) );
610 if ( !( stop
= strchr( line
, ':' ) ) ) {
614 DEBUG( 6, ( "parse_logentry: trying to parse [%s].\n", line
) );
616 if ( 0 == strncmp( start
, "LEN", stop
- start
) ) {
617 /* This will get recomputed later anyway -- probably not necessary */
618 entry
->record
.length
= atoi( stop
+ 1 );
619 } else if ( 0 == strncmp( start
, "RS1", stop
- start
) ) {
620 /* For now all these reserved entries seem to have the same value,
621 which can be hardcoded to int(1699505740) for now */
622 entry
->record
.reserved1
= atoi( stop
+ 1 );
623 } else if ( 0 == strncmp( start
, "RCN", stop
- start
) ) {
624 entry
->record
.record_number
= atoi( stop
+ 1 );
625 } else if ( 0 == strncmp( start
, "TMG", stop
- start
) ) {
626 entry
->record
.time_generated
= atoi( stop
+ 1 );
627 } else if ( 0 == strncmp( start
, "TMW", stop
- start
) ) {
628 entry
->record
.time_written
= atoi( stop
+ 1 );
629 } else if ( 0 == strncmp( start
, "EID", stop
- start
) ) {
630 entry
->record
.event_id
= atoi( stop
+ 1 );
631 } else if ( 0 == strncmp( start
, "ETP", stop
- start
) ) {
632 if ( strstr( start
, "ERROR" ) ) {
633 entry
->record
.event_type
= EVENTLOG_ERROR_TYPE
;
634 } else if ( strstr( start
, "WARNING" ) ) {
635 entry
->record
.event_type
= EVENTLOG_WARNING_TYPE
;
636 } else if ( strstr( start
, "INFO" ) ) {
637 entry
->record
.event_type
= EVENTLOG_INFORMATION_TYPE
;
638 } else if ( strstr( start
, "AUDIT_SUCCESS" ) ) {
639 entry
->record
.event_type
= EVENTLOG_AUDIT_SUCCESS
;
640 } else if ( strstr( start
, "AUDIT_FAILURE" ) ) {
641 entry
->record
.event_type
= EVENTLOG_AUDIT_FAILURE
;
642 } else if ( strstr( start
, "SUCCESS" ) ) {
643 entry
->record
.event_type
= EVENTLOG_SUCCESS
;
645 /* some other eventlog type -- currently not defined in MSDN docs, so error out */
651 else if(0 == strncmp(start, "NST", stop - start))
653 entry->record.num_strings = atoi(stop + 1);
656 else if ( 0 == strncmp( start
, "ECT", stop
- start
) ) {
657 entry
->record
.event_category
= atoi( stop
+ 1 );
658 } else if ( 0 == strncmp( start
, "RS2", stop
- start
) ) {
659 entry
->record
.reserved2
= atoi( stop
+ 1 );
660 } else if ( 0 == strncmp( start
, "CRN", stop
- start
) ) {
661 entry
->record
.closing_record_number
= atoi( stop
+ 1 );
662 } else if ( 0 == strncmp( start
, "USL", stop
- start
) ) {
663 entry
->record
.user_sid_length
= atoi( stop
+ 1 );
664 } else if ( 0 == strncmp( start
, "SRC", stop
- start
) ) {
665 memset( temp
, 0, sizeof( temp
) );
667 while ( isspace( stop
[0] ) ) {
670 temp_len
= strlen( stop
);
671 strncpy( temp
, stop
, temp_len
);
672 rpcstr_push( ( void * ) ( entry
->data_record
.source_name
),
673 temp
, sizeof( entry
->data_record
.source_name
),
675 entry
->data_record
.source_name_len
=
676 ( strlen_w( entry
->data_record
.source_name
) * 2 ) +
678 } else if ( 0 == strncmp( start
, "SRN", stop
- start
) ) {
679 memset( temp
, 0, sizeof( temp
) );
681 while ( isspace( stop
[0] ) ) {
684 temp_len
= strlen( stop
);
685 strncpy( temp
, stop
, temp_len
);
686 rpcstr_push( ( void * ) ( entry
->data_record
.computer_name
),
687 temp
, sizeof( entry
->data_record
.computer_name
),
689 entry
->data_record
.computer_name_len
=
690 ( strlen_w( entry
->data_record
.computer_name
) * 2 ) +
692 } else if ( 0 == strncmp( start
, "SID", stop
- start
) ) {
693 memset( temp
, 0, sizeof( temp
) );
695 while ( isspace( stop
[0] ) ) {
698 temp_len
= strlen( stop
);
699 strncpy( temp
, stop
, temp_len
);
700 rpcstr_push( ( void * ) ( entry
->data_record
.sid
), temp
,
701 sizeof( entry
->data_record
.sid
),
703 entry
->record
.user_sid_length
=
704 ( strlen_w( entry
->data_record
.sid
) * 2 ) + 2;
705 } else if ( 0 == strncmp( start
, "STR", stop
- start
) ) {
706 /* skip past initial ":" */
708 /* now skip any other leading whitespace */
709 while ( isspace( stop
[0] ) ) {
712 temp_len
= strlen( stop
);
713 memset( temp
, 0, sizeof( temp
) );
714 strncpy( temp
, stop
, temp_len
);
715 rpcstr_push( ( void * ) ( entry
->data_record
.strings
+
716 ( entry
->data_record
.strings_len
/ 2 ) ),
718 sizeof( entry
->data_record
.strings
) -
719 ( entry
->data_record
.strings_len
/ 2 ), STR_TERMINATE
);
720 entry
->data_record
.strings_len
+= ( temp_len
* 2 ) + 2;
721 entry
->record
.num_strings
++;
722 } else if ( 0 == strncmp( start
, "DAT", stop
- start
) ) {
723 /* skip past initial ":" */
725 /* now skip any other leading whitespace */
726 while ( isspace( stop
[0] ) ) {
729 entry
->data_record
.user_data_len
= strlen( stop
);
730 memset( entry
->data_record
.user_data
, 0,
731 sizeof( entry
->data_record
.user_data
) );
732 if ( entry
->data_record
.user_data_len
> 0 ) {
733 /* copy no more than the first 1024 bytes */
734 if ( entry
->data_record
.user_data_len
>
735 sizeof( entry
->data_record
.user_data
) )
736 entry
->data_record
.user_data_len
=
737 sizeof( entry
->data_record
.
739 memcpy( entry
->data_record
.user_data
, stop
,
740 entry
->data_record
.user_data_len
);
743 /* some other eventlog entry -- not implemented, so dropping on the floor */
744 DEBUG( 10, ( "Unknown entry [%s]. Ignoring.\n", line
) );
745 /* For now return true so that we can keep on parsing this mess. Eventually
746 we will return False here. */