r11761: * fix clearing of event logs by truncating the tdb.
[ira/wip.git] / source3 / rpc_server / srv_eventlog_lib.c
1 /* 
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.
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 /* maintain a list of open eventlog tdbs with reference counts */
26
27 static ELOG_TDB *open_elog_list;
28
29 /********************************************************************
30  Init an Eventlog TDB, and return it. If null, something bad 
31  happened.
32 ********************************************************************/
33
34 TDB_CONTEXT *elog_init_tdb( char *tdbfilename )
35 {
36         TDB_CONTEXT *tdb;
37
38         DEBUG(10,("elog_init_tdb: Initializing eventlog tdb (%s)\n",
39                 tdbfilename));
40
41         tdb = tdb_open_log( tdbfilename, 0, TDB_DEFAULT, 
42                 O_RDWR|O_CREAT|O_TRUNC, 0600 );
43
44         if ( !tdb ) {
45                 DEBUG( 0, ( "Can't open tdb for [%s]\n", tdbfilename ) );
46                 return NULL;
47         }
48
49         /* initialize with defaults, copy real values in here from registry */
50
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 );
55
56         tdb_store_int32( tdb, EVT_VERSION, EVENTLOG_DATABASE_VERSION_V1 );
57
58         return tdb;
59 }
60
61 /********************************************************************
62  make the tdb file name for an event log, given destination buffer 
63  and size. Caller must free memory.
64 ********************************************************************/
65
66 char *elog_tdbname( const char *name )
67 {
68         fstring path;
69         char *tdb_fullpath;
70         char *eventlogdir = lock_path( "eventlog" );
71         
72         pstr_sprintf( path, "%s/%s.tdb", eventlogdir, name );
73         strlower_m( path );
74         tdb_fullpath = SMB_STRDUP( path );
75         
76         return tdb_fullpath;
77 }
78
79
80 /********************************************************************
81  this function is used to count up the number of bytes in a 
82  particular TDB
83 ********************************************************************/
84
85 struct trav_size_struct {
86         int size;
87         int rec_count;
88 };
89
90 static int eventlog_tdb_size_fn( TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data,
91                           void *state )
92 {
93         struct trav_size_struct  *tsize = state;
94         
95         tsize->size += data.dsize;
96         tsize->rec_count++;
97         
98         return 0;
99 }
100
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. 
105  Yeah, that's it.
106 ********************************************************************/
107
108 int elog_tdb_size( TDB_CONTEXT * tdb, int *MaxSize, int *Retention )
109 {
110         struct trav_size_struct tsize;
111         
112         if ( !tdb )
113                 return 0;
114                 
115         ZERO_STRUCT( tsize );
116
117         tdb_traverse( tdb, eventlog_tdb_size_fn, &tsize );
118
119         if ( MaxSize != NULL ) {
120                 *MaxSize = tdb_fetch_int32( tdb, EVT_MAXSIZE );
121         }
122
123         if ( Retention != NULL ) {
124                 *Retention = tdb_fetch_int32( tdb, EVT_RETENTION );
125         }
126
127         DEBUG( 1,
128                ( "eventlog size: [%d] for [%d] records\n", tsize.size,
129                  tsize.rec_count ) );
130         return tsize.size;
131 }
132
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.  
138
139  Setting whack_by_date to True indicates that eventlogs falling 
140  outside of the retention range need to go...
141  
142  return True if we made enough room to accommodate needed bytes
143 ********************************************************************/
144
145 BOOL make_way_for_eventlogs( TDB_CONTEXT * the_tdb, int32 needed,
146                              BOOL whack_by_date )
147 {
148         int start_record, i, new_start;
149         int end_record;
150         int nbytes, reclen, len, Retention, MaxSize;
151         int tresv1, trecnum, timegen, timewr;
152         TDB_DATA key, ret;
153         TALLOC_CTX *mem_ctx = NULL;
154         time_t current_time, exp_time;
155
156         /* discard some eventlogs */
157
158         /* read eventlogs from oldest_entry -- there can't be any discontinuity in recnos,
159            although records not necessarily guaranteed to have successive times */
160         /* */
161         mem_ctx = talloc_init( "make_way_for_eventlogs" );      /* Homage to BPG */
162
163         if ( mem_ctx == NULL )
164                 return False;   /* can't allocate memory indicates bigger problems */
165         /* lock */
166         tdb_lock_bystring( the_tdb, EVT_NEXT_RECORD, 1 );
167         /* read */
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 );
172
173         time( &current_time );
174
175         /* calculate ... */
176         exp_time = current_time - Retention;    /* discard older than exp_time */
177
178         /* todo - check for sanity in next_record */
179         nbytes = 0;
180
181         DEBUG( 3,
182                ( "MaxSize [%d] Retention [%d] Current Time [%d]  exp_time [%d]\n",
183                  MaxSize, Retention, (uint32)current_time, (uint32)exp_time ) );
184         DEBUG( 3,
185                ( "Start Record [%d] End Record [%d]\n", start_record,
186                  end_record ) );
187
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 ) {
194                         DEBUG( 8,
195                                ( "Can't find a record for the key, record [%d]\n",
196                                  i ) );
197                         tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
198                         return False;
199                 }
200                 nbytes += ret.dsize;    /* note this includes overhead */
201
202                 len = tdb_unpack( ret.dptr, ret.dsize, "ddddd", &reclen,
203                                   &tresv1, &trecnum, &timegen, &timewr );
204                 DEBUG( 8,
205                        ( "read record %d, record size is [%d], total so far [%d]\n",
206                          i, reclen, nbytes ) );
207
208                 SAFE_FREE( ret.dptr );
209
210                 /* note that other servers may just stop writing records when the size limit
211                    is reached, and there are no records older than 'retention'. This doesn't 
212                    like a very useful thing to do, so instead we whack (as in sleeps with the 
213                    fishes) just enough records to fit the what we need.  This behavior could
214                    be changed to 'match', if the need arises. */
215
216                 if ( !whack_by_date && ( nbytes >= needed ) )
217                         break;  /* done */
218                 if ( whack_by_date && ( timegen >= exp_time ) )
219                         break;  /* done */
220         }
221
222         DEBUG( 3,
223                ( "nbytes [%d] needed [%d] start_record is [%d], should be set to [%d]\n",
224                  nbytes, needed, start_record, i ) );
225         /* todo - remove eventlog entries here and set starting record to start_record... */
226         new_start = i;
227         if ( start_record != new_start ) {
228                 for ( i = start_record; i < new_start; i++ ) {
229                         key.dsize = sizeof( int32 );
230                         key.dptr = ( char * ) ( int32 * ) & i;
231                         tdb_delete( the_tdb, key );
232                 }
233
234                 tdb_store_int32( the_tdb, EVT_OLDEST_ENTRY, new_start );
235         }
236         tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
237         return True;
238 }
239
240 /********************************************************************
241   some hygiene for an eventlog - see how big it is, and then 
242   calculate how many bytes we need to remove                   
243 ********************************************************************/
244
245 BOOL prune_eventlog( TDB_CONTEXT * tdb )
246 {
247         int MaxSize, Retention, CalcdSize;
248
249         if ( !tdb ) {
250                 DEBUG( 4, ( "No eventlog tdb handle\n" ) );
251                 return False;
252         }
253
254         CalcdSize = elog_tdb_size( tdb, &MaxSize, &Retention );
255         DEBUG( 3,
256                ( "Calculated size [%d] MaxSize [%d]\n", CalcdSize,
257                  MaxSize ) );
258
259         if ( CalcdSize > MaxSize ) {
260                 return make_way_for_eventlogs( tdb, CalcdSize - MaxSize,
261                                                False );
262         }
263
264         return make_way_for_eventlogs( tdb, 0, True );
265 }
266
267 /********************************************************************
268 ********************************************************************/
269
270 BOOL can_write_to_eventlog( TDB_CONTEXT * tdb, int32 needed )
271 {
272         int calcd_size;
273         int MaxSize, Retention;
274
275         /* see if we can write to the eventlog -- do a policy enforcement */
276         if ( !tdb )
277                 return False;   /* tdb is null, so we can't write to it */
278
279
280         if ( needed < 0 )
281                 return False;
282         MaxSize = 0;
283         Retention = 0;
284
285         calcd_size = elog_tdb_size( tdb, &MaxSize, &Retention );
286
287         if ( calcd_size <= MaxSize )
288                 return True;    /* you betcha */
289         if ( calcd_size + needed < MaxSize )
290                 return True;
291
292         if ( Retention == 0xffffffff ) {
293                 return False;   /* see msdn - we can't write no room, discard */
294         }
295         /*
296            note don't have to test, but always good to show intent, in case changes needed
297            later
298          */
299
300         if ( Retention == 0x00000000 ) {
301                 /* discard record(s) */
302                 /* todo  - decide when to remove a bunch vs. just what we need... */
303                 return make_way_for_eventlogs( tdb, calcd_size - MaxSize,
304                                                True );
305         }
306
307         return make_way_for_eventlogs( tdb, calcd_size - MaxSize, False );
308 }
309
310 /*******************************************************************
311 *******************************************************************/
312
313 ELOG_TDB *elog_open_tdb( char *logname, BOOL force_clear )
314 {
315         TDB_CONTEXT *tdb = NULL;
316         uint32 vers_id;
317         ELOG_TDB *ptr;
318         char *tdbfilename;
319         pstring tdbpath;
320         ELOG_TDB *tdb_node = NULL;
321         char *eventlogdir;
322
323         /* first see if we have an open context */
324         
325         for ( ptr=open_elog_list; ptr; ptr=ptr->next ) {
326                 if ( strequal( ptr->name, logname ) ) {
327                         ptr->ref_count++;
328
329                         /* trick to alow clearing of the eventlog tdb.
330                            The force_clear flag should imply that someone
331                            has done a force close.  So make sure the tdb 
332                            is NULL.  If this is a normal open, then just 
333                            return the existing reference */
334
335                         if ( force_clear ) {
336                                 SMB_ASSERT( ptr->tdb == NULL );
337                                 break;
338                         }
339                         else
340                                 return ptr;
341                 }
342         }
343         
344         /* make sure that the eventlog dir exists */
345         
346         eventlogdir = lock_path( "eventlog" );
347         if ( !directory_exist( eventlogdir, NULL ) )
348                 mkdir( eventlogdir, 0755 );     
349         
350         /* get the path on disk */
351         
352         tdbfilename = elog_tdbname( logname );
353         pstrcpy( tdbpath, tdbfilename );
354         SAFE_FREE( tdbfilename );
355
356         DEBUG(7,("elog_open_tdb: Opening %s...(force_clear == %s)\n", 
357                 tdbpath, force_clear?"True":"False" ));
358                 
359         /* the tdb wasn't already open or this is a forced clear open */
360
361         if ( !force_clear ) {
362
363                 tdb = tdb_open_log( tdbpath, 0, TDB_DEFAULT, O_RDWR , 0 );      
364                 if ( tdb ) {
365                         vers_id = tdb_fetch_int32( tdb, EVT_VERSION );
366
367                         if ( vers_id != EVENTLOG_DATABASE_VERSION_V1 ) {
368                                 DEBUG(1,("elog_open_tdb: Invalid version [%d] on file [%s].\n",
369                                         vers_id, tdbpath));
370                                 tdb_close( tdb );
371                                 tdb = elog_init_tdb( tdbpath );
372                         }
373                 }
374         }
375         
376         if ( !tdb )
377                 tdb = elog_init_tdb( tdbpath );
378         
379         /* if we got a valid context, then add it to the list */
380         
381         if ( tdb ) {
382                 /* on a forced clear, just reset the tdb context if we already
383                    have an open entry in the list */
384
385                 if ( ptr ) {
386                         ptr->tdb = tdb;
387                         return ptr;
388                 }
389
390                 if ( !(tdb_node = TALLOC_ZERO_P( NULL, ELOG_TDB)) ) {
391                         DEBUG(0,("elog_open_tdb: talloc() failure!\n"));
392                         tdb_close( tdb );
393                         return NULL;
394                 }
395                 
396                 tdb_node->name = talloc_strdup( tdb_node, logname );
397                 tdb_node->tdb = tdb;
398                 tdb_node->ref_count = 1;
399                 
400                 DLIST_ADD( open_elog_list, tdb_node );
401         }
402
403         return tdb_node;
404 }
405
406 /*******************************************************************
407  Wrapper to handle reference counts to the tdb
408 *******************************************************************/
409
410 int elog_close_tdb( ELOG_TDB *etdb, BOOL force_close )
411 {
412         TDB_CONTEXT *tdb;
413
414         if ( !etdb )
415                 return 0;
416                 
417         etdb->ref_count--;
418         
419         SMB_ASSERT( etdb->ref_count >= 0 );
420
421         if ( etdb->ref_count == 0 ) {
422                 tdb = etdb->tdb;
423                 DLIST_REMOVE( open_elog_list, etdb );
424                 TALLOC_FREE( etdb );
425                 return tdb_close( tdb );
426         }
427         
428         if ( force_close ) {
429                 tdb = etdb->tdb;
430                 etdb->tdb = NULL;
431                 return tdb_close( tdb );
432         }
433
434         return 0;
435 }
436
437
438 /*******************************************************************
439  write an eventlog entry. Note that we have to lock, read next 
440  eventlog, increment, write, write the record, unlock 
441  
442  coming into this, ee has the eventlog record, and the auxilliary date 
443  (computer name, etc.) filled into the other structure. Before packing 
444  into a record, this routine will calc the appropriate padding, etc., 
445  and then blast out the record in a form that can be read back in
446 *******************************************************************/
447  
448 #define MARGIN 512
449
450 int write_eventlog_tdb( TDB_CONTEXT * the_tdb, Eventlog_entry * ee )
451 {
452         int32 next_record;
453         uint8 *packed_ee;
454         TALLOC_CTX *mem_ctx = NULL;
455         TDB_DATA kbuf, ebuf;
456         uint32 n_packed;
457
458         if ( !ee )
459                 return 0;
460
461         mem_ctx = talloc_init( "write_eventlog_tdb" );
462
463         if ( mem_ctx == NULL )
464                 return 0;
465
466         if ( !ee )
467                 return 0;
468         /* discard any entries that have bogus time, which usually indicates a bogus entry as well. */
469         if ( ee->record.time_generated == 0 )
470                 return 0;
471
472         /* todo - check for sanity in next_record */
473
474         fixup_eventlog_entry( ee );
475
476         if ( !can_write_to_eventlog( the_tdb, ee->record.length ) ) {
477                 DEBUG( 3, ( "Can't write to Eventlog, no room \n" ) );
478                 talloc_destroy( mem_ctx );
479                 return 0;
480         }
481
482         /* alloc mem for the packed version */
483         packed_ee = TALLOC( mem_ctx, ee->record.length + MARGIN );
484         if ( !packed_ee ) {
485                 talloc_destroy( mem_ctx );
486                 return 0;
487         }
488
489         /* need to read the record number and insert it into the entry here */
490
491         /* lock */
492         tdb_lock_bystring( the_tdb, EVT_NEXT_RECORD, 1 );
493         /* read */
494         next_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
495
496         n_packed =
497                 tdb_pack( (char *)packed_ee, ee->record.length + MARGIN,
498                           "ddddddwwwwddddddBBdBBBd", ee->record.length,
499                           ee->record.reserved1, next_record,
500                           ee->record.time_generated, ee->record.time_written,
501                           ee->record.event_id, ee->record.event_type,
502                           ee->record.num_strings, ee->record.event_category,
503                           ee->record.reserved2,
504                           ee->record.closing_record_number,
505                           ee->record.string_offset,
506                           ee->record.user_sid_length,
507                           ee->record.user_sid_offset, ee->record.data_length,
508                           ee->record.data_offset,
509                           ee->data_record.source_name_len,
510                           ee->data_record.source_name,
511                           ee->data_record.computer_name_len,
512                           ee->data_record.computer_name,
513                           ee->data_record.sid_padding,
514                           ee->record.user_sid_length, ee->data_record.sid,
515                           ee->data_record.strings_len,
516                           ee->data_record.strings,
517                           ee->data_record.user_data_len,
518                           ee->data_record.user_data,
519                           ee->data_record.data_padding );
520
521         /*DEBUG(3,("write_eventlog_tdb: packed into  %d\n",n_packed)); */
522
523         /* increment the record count */
524
525         kbuf.dsize = sizeof( int32 );
526         kbuf.dptr = (char * ) & next_record;
527
528         ebuf.dsize = n_packed;
529         ebuf.dptr = (char *)packed_ee;
530
531         if ( tdb_store( the_tdb, kbuf, ebuf, 0 ) ) {
532                 /* DEBUG(1,("write_eventlog_tdb: Can't write record %d to eventlog\n",next_record)); */
533                 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
534                 talloc_destroy( mem_ctx );
535                 return 0;
536         }
537         next_record++;
538         tdb_store_int32( the_tdb, EVT_NEXT_RECORD, next_record );
539         tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
540         talloc_destroy( mem_ctx );
541         return ( next_record - 1 );
542 }
543
544 /*******************************************************************
545  calculate the correct fields etc for an eventlog entry
546 *******************************************************************/
547
548 void fixup_eventlog_entry( Eventlog_entry * ee )
549 {
550         /* fix up the eventlog entry structure as necessary */
551
552         ee->data_record.sid_padding =
553                 ( ( 4 -
554                     ( ( ee->data_record.source_name_len +
555                         ee->data_record.computer_name_len ) % 4 ) ) % 4 );
556         ee->data_record.data_padding =
557                 ( 4 -
558                   ( ( ee->data_record.strings_len +
559                       ee->data_record.user_data_len ) % 4 ) ) % 4;
560         ee->record.length = sizeof( Eventlog_record );
561         ee->record.length += ee->data_record.source_name_len;
562         ee->record.length += ee->data_record.computer_name_len;
563         if ( ee->record.user_sid_length == 0 ) {
564                 /* Should not pad to a DWORD boundary for writing out the sid if there is
565                    no SID, so just propagate the padding to pad the data */
566                 ee->data_record.data_padding += ee->data_record.sid_padding;
567                 ee->data_record.sid_padding = 0;
568         }
569         /* DEBUG(10, ("sid_padding is [%d].\n", ee->data_record.sid_padding)); */
570         /* DEBUG(10, ("data_padding is [%d].\n", ee->data_record.data_padding)); */
571
572         ee->record.length += ee->data_record.sid_padding;
573         ee->record.length += ee->record.user_sid_length;
574         ee->record.length += ee->data_record.strings_len;
575         ee->record.length += ee->data_record.user_data_len;
576         ee->record.length += ee->data_record.data_padding;
577         /* need another copy of length at the end of the data */
578         ee->record.length += sizeof( ee->record.length );
579 }
580
581 /********************************************************************
582  Note that it's a pretty good idea to initialize the Eventlog_entry 
583  structure to zero's before calling parse_logentry on an batch of 
584  lines that may resolve to a record.  ALSO, it's a good idea to 
585  remove any linefeeds (that's EOL to you and me) on the lines 
586  going in.
587 ********************************************************************/
588
589 BOOL parse_logentry( char *line, Eventlog_entry * entry, BOOL * eor )
590 {
591         char *start = NULL, *stop = NULL;
592         pstring temp;
593         int temp_len = 0;
594
595         start = line;
596
597         /* empty line signyfiying record delimeter, or we're at the end of the buffer */
598         if ( start == NULL || strlen( start ) == 0 ) {
599                 DEBUG( 6,
600                        ( "parse_logentry: found end-of-record indicator.\n" ) );
601                 *eor = True;
602                 return True;
603         }
604         if ( !( stop = strchr( line, ':' ) ) ) {
605                 return False;
606         }
607
608         DEBUG( 6, ( "parse_logentry: trying to parse [%s].\n", line ) );
609
610         if ( 0 == strncmp( start, "LEN", stop - start ) ) {
611                 /* This will get recomputed later anyway -- probably not necessary */
612                 entry->record.length = atoi( stop + 1 );
613         } else if ( 0 == strncmp( start, "RS1", stop - start ) ) {
614                 /* For now all these reserved entries seem to have the same value,
615                    which can be hardcoded to int(1699505740) for now */
616                 entry->record.reserved1 = atoi( stop + 1 );
617         } else if ( 0 == strncmp( start, "RCN", stop - start ) ) {
618                 entry->record.record_number = atoi( stop + 1 );
619         } else if ( 0 == strncmp( start, "TMG", stop - start ) ) {
620                 entry->record.time_generated = atoi( stop + 1 );
621         } else if ( 0 == strncmp( start, "TMW", stop - start ) ) {
622                 entry->record.time_written = atoi( stop + 1 );
623         } else if ( 0 == strncmp( start, "EID", stop - start ) ) {
624                 entry->record.event_id = atoi( stop + 1 );
625         } else if ( 0 == strncmp( start, "ETP", stop - start ) ) {
626                 if ( strstr( start, "ERROR" ) ) {
627                         entry->record.event_type = EVENTLOG_ERROR_TYPE;
628                 } else if ( strstr( start, "WARNING" ) ) {
629                         entry->record.event_type = EVENTLOG_WARNING_TYPE;
630                 } else if ( strstr( start, "INFO" ) ) {
631                         entry->record.event_type = EVENTLOG_INFORMATION_TYPE;
632                 } else if ( strstr( start, "AUDIT_SUCCESS" ) ) {
633                         entry->record.event_type = EVENTLOG_AUDIT_SUCCESS;
634                 } else if ( strstr( start, "AUDIT_FAILURE" ) ) {
635                         entry->record.event_type = EVENTLOG_AUDIT_FAILURE;
636                 } else if ( strstr( start, "SUCCESS" ) ) {
637                         entry->record.event_type = EVENTLOG_SUCCESS;
638                 } else {
639                         /* some other eventlog type -- currently not defined in MSDN docs, so error out */
640                         return False;
641                 }
642         }
643
644 /*
645   else if(0 == strncmp(start, "NST", stop - start))
646   {
647   entry->record.num_strings = atoi(stop + 1);
648   }
649 */
650         else if ( 0 == strncmp( start, "ECT", stop - start ) ) {
651                 entry->record.event_category = atoi( stop + 1 );
652         } else if ( 0 == strncmp( start, "RS2", stop - start ) ) {
653                 entry->record.reserved2 = atoi( stop + 1 );
654         } else if ( 0 == strncmp( start, "CRN", stop - start ) ) {
655                 entry->record.closing_record_number = atoi( stop + 1 );
656         } else if ( 0 == strncmp( start, "USL", stop - start ) ) {
657                 entry->record.user_sid_length = atoi( stop + 1 );
658         } else if ( 0 == strncmp( start, "SRC", stop - start ) ) {
659                 memset( temp, 0, sizeof( temp ) );
660                 stop++;
661                 while ( isspace( stop[0] ) ) {
662                         stop++;
663                 }
664                 temp_len = strlen( stop );
665                 strncpy( temp, stop, temp_len );
666                 rpcstr_push( ( void * ) ( entry->data_record.source_name ),
667                              temp, sizeof( entry->data_record.source_name ),
668                              STR_TERMINATE );
669                 entry->data_record.source_name_len =
670                         ( strlen_w( entry->data_record.source_name ) * 2 ) +
671                         2;
672         } else if ( 0 == strncmp( start, "SRN", stop - start ) ) {
673                 memset( temp, 0, sizeof( temp ) );
674                 stop++;
675                 while ( isspace( stop[0] ) ) {
676                         stop++;
677                 }
678                 temp_len = strlen( stop );
679                 strncpy( temp, stop, temp_len );
680                 rpcstr_push( ( void * ) ( entry->data_record.computer_name ),
681                              temp, sizeof( entry->data_record.computer_name ),
682                              STR_TERMINATE );
683                 entry->data_record.computer_name_len =
684                         ( strlen_w( entry->data_record.computer_name ) * 2 ) +
685                         2;
686         } else if ( 0 == strncmp( start, "SID", stop - start ) ) {
687                 memset( temp, 0, sizeof( temp ) );
688                 stop++;
689                 while ( isspace( stop[0] ) ) {
690                         stop++;
691                 }
692                 temp_len = strlen( stop );
693                 strncpy( temp, stop, temp_len );
694                 rpcstr_push( ( void * ) ( entry->data_record.sid ), temp,
695                              sizeof( entry->data_record.sid ),
696                              STR_TERMINATE );
697                 entry->record.user_sid_length =
698                         ( strlen_w( entry->data_record.sid ) * 2 ) + 2;
699         } else if ( 0 == strncmp( start, "STR", stop - start ) ) {
700                 /* skip past initial ":" */
701                 stop++;
702                 /* now skip any other leading whitespace */
703                 while ( isspace( stop[0] ) ) {
704                         stop++;
705                 }
706                 temp_len = strlen( stop );
707                 memset( temp, 0, sizeof( temp ) );
708                 strncpy( temp, stop, temp_len );
709                 rpcstr_push( ( void * ) ( entry->data_record.strings +
710                                           entry->data_record.strings_len ),
711                              temp,
712                              sizeof( entry->data_record.strings ) -
713                              entry->data_record.strings_len, STR_TERMINATE );
714                 entry->data_record.strings_len += temp_len + 1;
715                 entry->record.num_strings++;
716         } else if ( 0 == strncmp( start, "DAT", stop - start ) ) {
717                 /* Now that we're done processing the STR data, adjust the length to account for
718                    unicode, then proceed with the DAT data. */
719                 entry->data_record.strings_len *= 2;
720                 /* skip past initial ":" */
721                 stop++;
722                 /* now skip any other leading whitespace */
723                 while ( isspace( stop[0] ) ) {
724                         stop++;
725                 }
726                 entry->data_record.user_data_len = strlen( stop );
727                 memset( entry->data_record.user_data, 0,
728                         sizeof( entry->data_record.user_data ) );
729                 if ( entry->data_record.user_data_len > 0 ) {
730                         /* copy no more than the first 1024 bytes */
731                         if ( entry->data_record.user_data_len >
732                              sizeof( entry->data_record.user_data ) )
733                                 entry->data_record.user_data_len =
734                                         sizeof( entry->data_record.
735                                                 user_data );
736                         memcpy( entry->data_record.user_data, stop,
737                                 entry->data_record.user_data_len );
738                 }
739         } else {
740                 /* some other eventlog entry -- not implemented, so dropping on the floor */
741                 DEBUG( 10, ( "Unknown entry [%s]. Ignoring.\n", line ) );
742                 /* For now return true so that we can keep on parsing this mess. Eventually
743                    we will return False here. */
744                 return True;
745         }
746         return True;
747 }