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