r10795: Fix code before decl error.
[ira/wip.git] / source3 / rpc_server / srv_eventlog_lib.c
1
2 /* 
3  *  Unix SMB/CIFS implementation.
4  *  Eventlog utility  routines
5  *  Copyright (C) Marcin Krzysztof Porwit    2005,
6  *  Copyright (C) Gerald (Jerry) Carter      2005.
7  *  
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.
12  *  
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.
17  *  
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.
21  */
22
23 #include "includes.h"
24
25
26 /****************************************************************
27 Init an Eventlog TDB, and return it. If null, something bad happened.
28 ****************************************************************/
29 TDB_CONTEXT *init_eventlog_tdb( char *tdbfilename )
30 {
31         TDB_CONTEXT *the_tdb;
32
33         unlink( tdbfilename );
34
35         the_tdb =
36                 tdb_open_log( tdbfilename, 0, TDB_DEFAULT, O_RDWR | O_CREAT,
37                               0664 );
38         if ( the_tdb == NULL ) {
39                 DEBUG( 1, ( "Can't open tdb for [%s]\n", tdbfilename ) );
40                 return NULL;
41         }
42         tdb_store_int32( the_tdb, VN_oldest_entry, 1 );
43         tdb_store_int32( the_tdb, VN_next_record, 1 );
44
45         /* initialize with defaults, copy real values in here from registry */
46
47         tdb_store_int32( the_tdb, VN_maxsize, 0x80000 );
48         tdb_store_int32( the_tdb, VN_retention, 0x93A80 );
49
50         tdb_store_int32( the_tdb, VN_version, EVENTLOG_DATABASE_VERSION_V1 );
51         return the_tdb;
52 }
53
54 /* make the tdb file name for an event log, given destination buffer and size */
55 char *mk_tdbfilename( char *dest_buffer, char *eventlog_name, int size_dest )
56 {
57         pstring ondisk_name;
58
59         if ( !dest_buffer )
60                 return NULL;
61
62         pstrcpy( ondisk_name, "EV" );
63         pstrcat( ondisk_name, eventlog_name );
64         pstrcat( ondisk_name, ".tdb" );
65
66         memset( dest_buffer, 0, size_dest );
67
68         /* BAD things could happen if the dest_buffer is not large enough... */
69         if ( strlen( ondisk_name ) > size_dest ) {
70                 DEBUG( 3, ( "Buffer not big enough for filename\n" ) );
71                 return NULL;
72         }
73
74         strncpy( dest_buffer, ondisk_name, size_dest );
75
76         return dest_buffer;
77 }
78
79
80 /* count the number of bytes in the TDB */
81
82 /* Arg! Static Globals! */
83
84 static int eventlog_tdbcount;
85 static int eventlog_tdbsize;
86
87 /* this function is used to count up the number of bytes in a particular TDB */
88 int eventlog_tdb_size_fn( TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data,
89                           void *state )
90 {
91         eventlog_tdbsize += data.dsize;
92         eventlog_tdbcount++;
93         return 0;
94 }
95
96 /* returns the size of the eventlog, and if MaxSize is a non-null ptr, puts 
97    the MaxSize there. This is purely a way not to have yet another function that solely
98    reads the maxsize of the eventlog. Yeah, that's it.  */
99
100 int eventlog_tdb_size( TDB_CONTEXT * tdb, int *MaxSize, int *Retention )
101 {
102         if ( !tdb )
103                 return 0;
104         eventlog_tdbcount = 0;
105         eventlog_tdbsize = 0;
106
107         tdb_traverse( tdb, eventlog_tdb_size_fn, NULL );
108
109         if ( MaxSize != NULL ) {
110                 *MaxSize = tdb_fetch_int32( tdb, VN_maxsize );
111         }
112
113         if ( Retention != NULL ) {
114                 *Retention = tdb_fetch_int32( tdb, VN_retention );
115         }
116
117         DEBUG( 1,
118                ( "eventlog size: [%d] for [%d] records\n", eventlog_tdbsize,
119                  eventlog_tdbcount ) );
120         return eventlog_tdbsize;
121 }
122
123
124 /* 
125    Discard early event logs until we have enough for 'needed' bytes...
126    NO checking done beforehand to see that we actually need to do this, and
127    it's going to pluck records one-by-one. So, it's best to determine that this 
128    needs to be done before doing it.  
129
130    Setting whack_by_date to True indicates that eventlogs falling outside of the 
131    retention range need to go...
132
133 */
134
135 /* return True if we made enough room to accommodate needed bytes */
136
137 BOOL make_way_for_eventlogs( TDB_CONTEXT * the_tdb, int32 needed,
138                              BOOL whack_by_date )
139 {
140         int start_record, i, new_start;
141         int end_record;
142         int nbytes, reclen, len, Retention, MaxSize;
143
144         int tresv1, trecnum, timegen, timewr;
145
146         TDB_DATA key, ret;
147         TALLOC_CTX *mem_ctx = NULL;
148
149         time_t current_time, exp_time;
150
151         /* discard some eventlogs */
152
153         /* read eventlogs from oldest_entry -- there can't be any discontinuity in recnos,
154            although records not necessarily guaranteed to have successive times */
155         /* */
156         mem_ctx = talloc_init( "make_way_for_eventlogs" );      /* Homage to BPG */
157
158         if ( mem_ctx == NULL )
159                 return False;   /* can't allocate memory indicates bigger problems */
160         /* lock */
161         tdb_lock_bystring( the_tdb, VN_next_record, 1 );
162         /* read */
163         end_record = tdb_fetch_int32( the_tdb, VN_next_record );
164         start_record = tdb_fetch_int32( the_tdb, VN_oldest_entry );
165         Retention = tdb_fetch_int32( the_tdb, VN_retention );
166         MaxSize = tdb_fetch_int32( the_tdb, VN_maxsize );
167
168         time( &current_time );
169
170         /* calculate ... */
171         exp_time = current_time - Retention;    /* discard older than exp_time */
172
173         /* todo - check for sanity in next_record */
174         nbytes = 0;
175
176         DEBUG( 3,
177                ( "MaxSize [%d] Retention [%d] Current Time [%d]  exp_time [%d]\n",
178                  MaxSize, Retention, (uint32)current_time, (uint32)exp_time ) );
179         DEBUG( 3,
180                ( "Start Record [%d] End Record [%d]\n", start_record,
181                  end_record ) );
182
183         for ( i = start_record; i < end_record; i++ ) {
184                 /* read a record, add the amt to nbytes */
185                 key.dsize = sizeof( int32 );
186                 key.dptr = ( char * ) ( int32 * ) & i;
187                 ret = tdb_fetch( the_tdb, key );
188                 if ( ret.dsize == 0 ) {
189                         DEBUG( 8,
190                                ( "Can't find a record for the key, record [%d]\n",
191                                  i ) );
192                         tdb_unlock_bystring( the_tdb, VN_next_record );
193                         return False;
194                 }
195                 nbytes += ret.dsize;    /* note this includes overhead */
196
197                 len = tdb_unpack( ret.dptr, ret.dsize, "ddddd", &reclen,
198                                   &tresv1, &trecnum, &timegen, &timewr );
199                 DEBUG( 8,
200                        ( "read record %d, record size is [%d], total so far [%d]\n",
201                          i, reclen, nbytes ) );
202
203                 SAFE_FREE( ret.dptr );
204
205                 /* note that other servers may just stop writing records when the size limit
206                    is reached, and there are no records older than 'retention'. This doesn't 
207                    like a very useful thing to do, so instead we whack (as in sleeps with the 
208                    fishes) just enough records to fit the what we need.  This behavior could
209                    be changed to 'match', if the need arises. */
210
211                 if ( !whack_by_date && ( nbytes >= needed ) )
212                         break;  /* done */
213                 if ( whack_by_date && ( timegen >= exp_time ) )
214                         break;  /* done */
215         }
216
217         DEBUG( 3,
218                ( "nbytes [%d] needed [%d] start_record is [%d], should be set to [%d]\n",
219                  nbytes, needed, start_record, i ) );
220         /* todo - remove eventlog entries here and set starting record to start_record... */
221         new_start = i;
222         if ( start_record != new_start ) {
223                 for ( i = start_record; i < new_start; i++ ) {
224                         key.dsize = sizeof( int32 );
225                         key.dptr = ( char * ) ( int32 * ) & i;
226                         tdb_delete( the_tdb, key );
227                 }
228
229                 tdb_store_int32( the_tdb, VN_oldest_entry, new_start );
230         }
231         tdb_unlock_bystring( the_tdb, VN_next_record );
232         return True;
233 }
234
235 /*
236   some hygiene for an eventlog - see how big it is, and then 
237   calculate how many bytes we need to remove                   
238 */
239
240 BOOL prune_eventlog( TDB_CONTEXT * tdb )
241 {
242         int MaxSize, Retention, CalcdSize;
243
244         if ( !tdb ) {
245                 DEBUG( 4, ( "No eventlog tdb handle\n" ) );
246                 return False;
247         }
248
249         CalcdSize = eventlog_tdb_size( tdb, &MaxSize, &Retention );
250         DEBUG( 3,
251                ( "Calculated size [%d] MaxSize [%d]\n", CalcdSize,
252                  MaxSize ) );
253
254         if ( CalcdSize > MaxSize ) {
255                 return make_way_for_eventlogs( tdb, CalcdSize - MaxSize,
256                                                False );
257         }
258
259         return make_way_for_eventlogs( tdb, 0, True );
260 }
261
262 BOOL can_write_to_eventlog( TDB_CONTEXT * tdb, int32 needed )
263 {
264         int calcd_size;
265         int MaxSize, Retention;
266
267         /* see if we can write to the eventlog -- do a policy enforcement */
268         if ( !tdb )
269                 return False;   /* tdb is null, so we can't write to it */
270
271
272         if ( needed < 0 )
273                 return False;
274         MaxSize = 0;
275         Retention = 0;
276
277         calcd_size = eventlog_tdb_size( tdb, &MaxSize, &Retention );
278
279         if ( calcd_size <= MaxSize )
280                 return True;    /* you betcha */
281         if ( calcd_size + needed < MaxSize )
282                 return True;
283
284         if ( Retention == 0xffffffff ) {
285                 return False;   /* see msdn - we can't write no room, discard */
286         }
287         /*
288            note don't have to test, but always good to show intent, in case changes needed
289            later
290          */
291
292         if ( Retention == 0x00000000 ) {
293                 /* discard record(s) */
294                 /* todo  - decide when to remove a bunch vs. just what we need... */
295                 return make_way_for_eventlogs( tdb, calcd_size - MaxSize,
296                                                True );
297         }
298
299         return make_way_for_eventlogs( tdb, calcd_size - MaxSize, False );
300 }
301
302 TDB_CONTEXT *open_eventlog_tdb( char *tdbfilename )
303 {
304         TDB_CONTEXT *the_tdb;
305
306         the_tdb =
307                 tdb_open_log( tdbfilename, 0, TDB_DEFAULT, O_RDWR | O_CREAT,
308                               0664 );
309         if ( the_tdb == NULL ) {
310                 return init_eventlog_tdb( tdbfilename );
311         }
312         if ( EVENTLOG_DATABASE_VERSION_V1 !=
313              tdb_fetch_int32( the_tdb, VN_version ) ) {
314                 tdb_close( the_tdb );
315                 return init_eventlog_tdb( tdbfilename );
316         }
317         return the_tdb;
318 }
319
320 /* write an eventlog entry. Note that we have to lock, read next eventlog, increment, write, write the record, unlock */
321
322 /* coming into this, ee has the eventlog record, and the auxilliary date (computer name, etc.) 
323    filled into the other structure. Before packing into a record, this routine will calc the 
324    appropriate padding, etc., and then blast out the record in a form that can be read back in */
325 int write_eventlog_tdb( TDB_CONTEXT * the_tdb, Eventlog_entry * ee )
326 {
327         int32 next_record;
328         uint8 *packed_ee;
329         TALLOC_CTX *mem_ctx = NULL;
330         TDB_DATA kbuf, ebuf;
331         uint32 n_packed;
332
333         if ( !ee )
334                 return 0;
335
336         mem_ctx = talloc_init( "write_eventlog_tdb" );
337
338         if ( mem_ctx == NULL )
339                 return 0;
340
341         if ( !ee )
342                 return 0;
343         /* discard any entries that have bogus time, which usually indicates a bogus entry as well. */
344         if ( ee->record.time_generated == 0 )
345                 return 0;
346
347 #define MARGIN 512
348
349         /* todo - check for sanity in next_record */
350
351         fixup_eventlog_entry( ee );
352
353         if ( !can_write_to_eventlog( the_tdb, ee->record.length ) ) {
354                 DEBUG( 3, ( "Can't write to Eventlog, no room \n" ) );
355                 talloc_destroy( mem_ctx );
356                 return 0;
357         }
358
359         /* alloc mem for the packed version */
360         packed_ee = TALLOC( mem_ctx, ee->record.length + MARGIN );
361         if ( !packed_ee ) {
362                 talloc_destroy( mem_ctx );
363                 return 0;
364         }
365
366         /* need to read the record number and insert it into the entry here */
367
368         /* lock */
369         tdb_lock_bystring( the_tdb, VN_next_record, 1 );
370         /* read */
371         next_record = tdb_fetch_int32( the_tdb, VN_next_record );
372
373         n_packed =
374                 tdb_pack( packed_ee, ee->record.length + MARGIN,
375                           "ddddddwwwwddddddBBdBBBd", ee->record.length,
376                           ee->record.reserved1, next_record,
377                           ee->record.time_generated, ee->record.time_written,
378                           ee->record.event_id, ee->record.event_type,
379                           ee->record.num_strings, ee->record.event_category,
380                           ee->record.reserved2,
381                           ee->record.closing_record_number,
382                           ee->record.string_offset,
383                           ee->record.user_sid_length,
384                           ee->record.user_sid_offset, ee->record.data_length,
385                           ee->record.data_offset,
386                           ee->data_record.source_name_len,
387                           ee->data_record.source_name,
388                           ee->data_record.computer_name_len,
389                           ee->data_record.computer_name,
390                           ee->data_record.sid_padding,
391                           ee->record.user_sid_length, ee->data_record.sid,
392                           ee->data_record.strings_len,
393                           ee->data_record.strings,
394                           ee->data_record.user_data_len,
395                           ee->data_record.user_data,
396                           ee->data_record.data_padding );
397
398         /*DEBUG(3,("write_eventlog_tdb: packed into  %d\n",n_packed)); */
399
400         /* increment the record count */
401
402         kbuf.dsize = sizeof( int32 );
403         kbuf.dptr = ( uint8 * ) & next_record;
404
405         ebuf.dsize = n_packed;
406         ebuf.dptr = packed_ee;
407
408         if ( tdb_store( the_tdb, kbuf, ebuf, 0 ) ) {
409                 /* DEBUG(1,("write_eventlog_tdb: Can't write record %d to eventlog\n",next_record)); */
410                 tdb_unlock_bystring( the_tdb, VN_next_record );
411                 talloc_destroy( mem_ctx );
412                 return 0;
413         }
414         next_record++;
415         tdb_store_int32( the_tdb, VN_next_record, next_record );
416         tdb_unlock_bystring( the_tdb, VN_next_record );
417         talloc_destroy( mem_ctx );
418         return ( next_record - 1 );
419 }
420
421 /* calculate the correct fields etc for an eventlog entry */
422
423 void fixup_eventlog_entry( Eventlog_entry * ee )
424 {
425         /* fix up the eventlog entry structure as necessary */
426
427         ee->data_record.sid_padding =
428                 ( ( 4 -
429                     ( ( ee->data_record.source_name_len +
430                         ee->data_record.computer_name_len ) % 4 ) ) % 4 );
431         ee->data_record.data_padding =
432                 ( 4 -
433                   ( ( ee->data_record.strings_len +
434                       ee->data_record.user_data_len ) % 4 ) ) % 4;
435         ee->record.length = sizeof( Eventlog_record );
436         ee->record.length += ee->data_record.source_name_len;
437         ee->record.length += ee->data_record.computer_name_len;
438         if ( ee->record.user_sid_length == 0 ) {
439                 /* Should not pad to a DWORD boundary for writing out the sid if there is
440                    no SID, so just propagate the padding to pad the data */
441                 ee->data_record.data_padding += ee->data_record.sid_padding;
442                 ee->data_record.sid_padding = 0;
443         }
444         /* DEBUG(10, ("sid_padding is [%d].\n", ee->data_record.sid_padding)); */
445         /* DEBUG(10, ("data_padding is [%d].\n", ee->data_record.data_padding)); */
446
447         ee->record.length += ee->data_record.sid_padding;
448         ee->record.length += ee->record.user_sid_length;
449         ee->record.length += ee->data_record.strings_len;
450         ee->record.length += ee->data_record.user_data_len;
451         ee->record.length += ee->data_record.data_padding;
452         /* need another copy of length at the end of the data */
453         ee->record.length += sizeof( ee->record.length );
454 }
455
456 /********************************************************************
457 Note that it's a pretty good idea to initialize the Eventlog_entry structure to zero's before
458 calling parse_logentry on an batch of lines that may resolve to a record.
459 ALSO, it's a good idea to remove any linefeeds (that's EOL to you and me) on the lines going in.
460
461 ********************************************************************/
462
463 BOOL parse_logentry( char *line, Eventlog_entry * entry, BOOL * eor )
464 {
465         char *start = NULL, *stop = NULL;
466         pstring temp;
467         int temp_len = 0;
468
469         start = line;
470
471         /* empty line signyfiying record delimeter, or we're at the end of the buffer */
472         if ( start == NULL || strlen( start ) == 0 ) {
473                 DEBUG( 6,
474                        ( "parse_logentry: found end-of-record indicator.\n" ) );
475                 *eor = True;
476                 return True;
477         }
478         if ( !( stop = strchr( line, ':' ) ) ) {
479                 return False;
480         }
481
482         DEBUG( 6, ( "parse_logentry: trying to parse [%s].\n", line ) );
483
484         if ( 0 == strncmp( start, "LEN", stop - start ) ) {
485                 /* This will get recomputed later anyway -- probably not necessary */
486                 entry->record.length = atoi( stop + 1 );
487         } else if ( 0 == strncmp( start, "RS1", stop - start ) ) {
488                 /* For now all these reserved entries seem to have the same value,
489                    which can be hardcoded to int(1699505740) for now */
490                 entry->record.reserved1 = atoi( stop + 1 );
491         } else if ( 0 == strncmp( start, "RCN", stop - start ) ) {
492                 entry->record.record_number = atoi( stop + 1 );
493         } else if ( 0 == strncmp( start, "TMG", stop - start ) ) {
494                 entry->record.time_generated = atoi( stop + 1 );
495         } else if ( 0 == strncmp( start, "TMW", stop - start ) ) {
496                 entry->record.time_written = atoi( stop + 1 );
497         } else if ( 0 == strncmp( start, "EID", stop - start ) ) {
498                 entry->record.event_id = atoi( stop + 1 );
499         } else if ( 0 == strncmp( start, "ETP", stop - start ) ) {
500                 if ( strstr( start, "ERROR" ) ) {
501                         entry->record.event_type = EVENTLOG_ERROR_TYPE;
502                 } else if ( strstr( start, "WARNING" ) ) {
503                         entry->record.event_type = EVENTLOG_WARNING_TYPE;
504                 } else if ( strstr( start, "INFO" ) ) {
505                         entry->record.event_type = EVENTLOG_INFORMATION_TYPE;
506                 } else if ( strstr( start, "AUDIT_SUCCESS" ) ) {
507                         entry->record.event_type = EVENTLOG_AUDIT_SUCCESS;
508                 } else if ( strstr( start, "AUDIT_FAILURE" ) ) {
509                         entry->record.event_type = EVENTLOG_AUDIT_FAILURE;
510                 } else if ( strstr( start, "SUCCESS" ) ) {
511                         entry->record.event_type = EVENTLOG_SUCCESS;
512                 } else {
513                         /* some other eventlog type -- currently not defined in MSDN docs, so error out */
514                         return False;
515                 }
516         }
517
518 /*
519   else if(0 == strncmp(start, "NST", stop - start))
520   {
521   entry->record.num_strings = atoi(stop + 1);
522   }
523 */
524         else if ( 0 == strncmp( start, "ECT", stop - start ) ) {
525                 entry->record.event_category = atoi( stop + 1 );
526         } else if ( 0 == strncmp( start, "RS2", stop - start ) ) {
527                 entry->record.reserved2 = atoi( stop + 1 );
528         } else if ( 0 == strncmp( start, "CRN", stop - start ) ) {
529                 entry->record.closing_record_number = atoi( stop + 1 );
530         } else if ( 0 == strncmp( start, "USL", stop - start ) ) {
531                 entry->record.user_sid_length = atoi( stop + 1 );
532         } else if ( 0 == strncmp( start, "SRC", stop - start ) ) {
533                 memset( temp, 0, sizeof( temp ) );
534                 stop++;
535                 while ( isspace( stop[0] ) ) {
536                         stop++;
537                 }
538                 temp_len = strlen( stop );
539                 strncpy( temp, stop, temp_len );
540                 rpcstr_push( ( void * ) ( entry->data_record.source_name ),
541                              temp, sizeof( entry->data_record.source_name ),
542                              STR_TERMINATE );
543                 entry->data_record.source_name_len =
544                         ( strlen_w( entry->data_record.source_name ) * 2 ) +
545                         2;
546         } else if ( 0 == strncmp( start, "SRN", stop - start ) ) {
547                 memset( temp, 0, sizeof( temp ) );
548                 stop++;
549                 while ( isspace( stop[0] ) ) {
550                         stop++;
551                 }
552                 temp_len = strlen( stop );
553                 strncpy( temp, stop, temp_len );
554                 rpcstr_push( ( void * ) ( entry->data_record.computer_name ),
555                              temp, sizeof( entry->data_record.computer_name ),
556                              STR_TERMINATE );
557                 entry->data_record.computer_name_len =
558                         ( strlen_w( entry->data_record.computer_name ) * 2 ) +
559                         2;
560         } else if ( 0 == strncmp( start, "SID", stop - start ) ) {
561                 memset( temp, 0, sizeof( temp ) );
562                 stop++;
563                 while ( isspace( stop[0] ) ) {
564                         stop++;
565                 }
566                 temp_len = strlen( stop );
567                 strncpy( temp, stop, temp_len );
568                 rpcstr_push( ( void * ) ( entry->data_record.sid ), temp,
569                              sizeof( entry->data_record.sid ),
570                              STR_TERMINATE );
571                 entry->record.user_sid_length =
572                         ( strlen_w( entry->data_record.sid ) * 2 ) + 2;
573         } else if ( 0 == strncmp( start, "STR", stop - start ) ) {
574                 /* skip past initial ":" */
575                 stop++;
576                 /* now skip any other leading whitespace */
577                 while ( isspace( stop[0] ) ) {
578                         stop++;
579                 }
580                 temp_len = strlen( stop );
581                 memset( temp, 0, sizeof( temp ) );
582                 strncpy( temp, stop, temp_len );
583                 rpcstr_push( ( void * ) ( entry->data_record.strings +
584                                           entry->data_record.strings_len ),
585                              temp,
586                              sizeof( entry->data_record.strings ) -
587                              entry->data_record.strings_len, STR_TERMINATE );
588                 entry->data_record.strings_len += temp_len + 1;
589                 entry->record.num_strings++;
590         } else if ( 0 == strncmp( start, "DAT", stop - start ) ) {
591                 /* Now that we're done processing the STR data, adjust the length to account for
592                    unicode, then proceed with the DAT data. */
593                 entry->data_record.strings_len *= 2;
594                 /* skip past initial ":" */
595                 stop++;
596                 /* now skip any other leading whitespace */
597                 while ( isspace( stop[0] ) ) {
598                         stop++;
599                 }
600                 entry->data_record.user_data_len = strlen( stop );
601                 memset( entry->data_record.user_data, 0,
602                         sizeof( entry->data_record.user_data ) );
603                 if ( entry->data_record.user_data_len > 0 ) {
604                         /* copy no more than the first 1024 bytes */
605                         if ( entry->data_record.user_data_len >
606                              sizeof( entry->data_record.user_data ) )
607                                 entry->data_record.user_data_len =
608                                         sizeof( entry->data_record.
609                                                 user_data );
610                         memcpy( entry->data_record.user_data, stop,
611                                 entry->data_record.user_data_len );
612                 }
613         } else {
614                 /* some other eventlog entry -- not implemented, so dropping on the floor */
615                 DEBUG( 10, ( "Unknown entry [%s]. Ignoring.\n", line ) );
616                 /* For now return true so that we can keep on parsing this mess. Eventually
617                    we will return False here. */
618                 return True;
619         }
620         return True;
621 }