Make make_way_for_eventlogs() static
[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 3 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, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "includes.h"
23
24 /* maintain a list of open eventlog tdbs with reference counts */
25
26 static ELOG_TDB *open_elog_list;
27
28 /********************************************************************
29  Init an Eventlog TDB, and return it. If null, something bad 
30  happened.
31 ********************************************************************/
32
33 TDB_CONTEXT *elog_init_tdb( char *tdbfilename )
34 {
35         TDB_CONTEXT *tdb;
36
37         DEBUG(10,("elog_init_tdb: Initializing eventlog tdb (%s)\n",
38                 tdbfilename));
39
40         tdb = tdb_open_log( tdbfilename, 0, TDB_DEFAULT, 
41                 O_RDWR|O_CREAT|O_TRUNC, 0660 );
42
43         if ( !tdb ) {
44                 DEBUG( 0, ( "Can't open tdb for [%s]\n", tdbfilename ) );
45                 return NULL;
46         }
47
48         /* initialize with defaults, copy real values in here from registry */
49
50         tdb_store_int32( tdb, EVT_OLDEST_ENTRY, 1 );
51         tdb_store_int32( tdb, EVT_NEXT_RECORD, 1 );
52         tdb_store_int32( tdb, EVT_MAXSIZE, 0x80000 );
53         tdb_store_int32( tdb, EVT_RETENTION, 0x93A80 );
54
55         tdb_store_int32( tdb, EVT_VERSION, EVENTLOG_DATABASE_VERSION_V1 );
56
57         return tdb;
58 }
59
60 /********************************************************************
61  make the tdb file name for an event log, given destination buffer 
62  and size. Caller must free memory.
63 ********************************************************************/
64
65 char *elog_tdbname(TALLOC_CTX *ctx, const char *name )
66 {
67         char *path = talloc_asprintf(ctx, "%s/%s.tdb",
68                         state_path("eventlog"),
69                         name);
70         if (!path) {
71                 return NULL;
72         }
73         strlower_m(path);
74         return path;
75 }
76
77
78 /********************************************************************
79  this function is used to count up the number of bytes in a 
80  particular TDB
81 ********************************************************************/
82
83 struct trav_size_struct {
84         int size;
85         int rec_count;
86 };
87
88 static int eventlog_tdb_size_fn( TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data,
89                           void *state )
90 {
91         struct trav_size_struct  *tsize = (struct trav_size_struct *)state;
92         
93         tsize->size += data.dsize;
94         tsize->rec_count++;
95         
96         return 0;
97 }
98
99 /********************************************************************
100  returns the size of the eventlog, and if MaxSize is a non-null 
101  ptr, puts the MaxSize there. This is purely a way not to have yet 
102  another function that solely reads the maxsize of the eventlog. 
103  Yeah, that's it.
104 ********************************************************************/
105
106 int elog_tdb_size( TDB_CONTEXT * tdb, int *MaxSize, int *Retention )
107 {
108         struct trav_size_struct tsize;
109         
110         if ( !tdb )
111                 return 0;
112                 
113         ZERO_STRUCT( tsize );
114
115         tdb_traverse( tdb, eventlog_tdb_size_fn, &tsize );
116
117         if ( MaxSize != NULL ) {
118                 *MaxSize = tdb_fetch_int32( tdb, EVT_MAXSIZE );
119         }
120
121         if ( Retention != NULL ) {
122                 *Retention = tdb_fetch_int32( tdb, EVT_RETENTION );
123         }
124
125         DEBUG( 1,
126                ( "eventlog size: [%d] for [%d] records\n", tsize.size,
127                  tsize.rec_count ) );
128         return tsize.size;
129 }
130
131 /********************************************************************
132  Discard early event logs until we have enough for 'needed' bytes...
133  NO checking done beforehand to see that we actually need to do 
134  this, and it's going to pluck records one-by-one. So, it's best 
135  to determine that this needs to be done before doing it.  
136
137  Setting whack_by_date to True indicates that eventlogs falling 
138  outside of the retention range need to go...
139  
140  return True if we made enough room to accommodate needed bytes
141 ********************************************************************/
142
143 static bool make_way_for_eventlogs( TDB_CONTEXT * the_tdb, int32 needed,
144                                     bool whack_by_date )
145 {
146         int start_record, i, new_start;
147         int end_record;
148         int nbytes, reclen, len, Retention, MaxSize;
149         int tresv1, trecnum, timegen, timewr;
150         TDB_DATA key, ret;
151         time_t current_time, exp_time;
152
153         /* discard some eventlogs */
154
155         /* read eventlogs from oldest_entry -- there can't be any discontinuity in recnos,
156            although records not necessarily guaranteed to have successive times */
157         /* */
158
159         /* lock */
160         tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
161         /* read */
162         end_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
163         start_record = tdb_fetch_int32( the_tdb, EVT_OLDEST_ENTRY );
164         Retention = tdb_fetch_int32( the_tdb, EVT_RETENTION );
165         MaxSize = tdb_fetch_int32( the_tdb, EVT_MAXSIZE );
166
167         time( &current_time );
168
169         /* calculate ... */
170         exp_time = current_time - Retention;    /* discard older than exp_time */
171
172         /* todo - check for sanity in next_record */
173         nbytes = 0;
174
175         DEBUG( 3,
176                ( "MaxSize [%d] Retention [%d] Current Time [%d]  exp_time [%d]\n",
177                  MaxSize, Retention, (uint32)current_time, (uint32)exp_time ) );
178         DEBUG( 3,
179                ( "Start Record [%d] End Record [%d]\n", start_record,
180                  end_record ) );
181
182         for ( i = start_record; i < end_record; i++ ) {
183                 /* read a record, add the amt to nbytes */
184                 key.dsize = sizeof( int32 );
185                 key.dptr = ( uint8 * ) ( int32 * ) & i;
186                 ret = tdb_fetch( the_tdb, key );
187                 if ( ret.dsize == 0 ) {
188                         DEBUG( 8,
189                                ( "Can't find a record for the key, record [%d]\n",
190                                  i ) );
191                         tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
192                         return False;
193                 }
194                 nbytes += ret.dsize;    /* note this includes overhead */
195
196                 len = tdb_unpack( ret.dptr, ret.dsize, "ddddd", &reclen,
197                                   &tresv1, &trecnum, &timegen, &timewr );
198                 if (len == -1) {
199                         DEBUG( 10,("make_way_for_eventlogs: tdb_unpack failed.\n"));
200                         tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
201                         return False;
202                 }
203
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 = ( uint8 * ) ( 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 *tdbpath = NULL;
319         ELOG_TDB *tdb_node = NULL;
320         char *eventlogdir;
321         TALLOC_CTX *ctx = talloc_tos();
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 = state_path( "eventlog" );
347         if ( !directory_exist( eventlogdir, NULL ) )
348                 mkdir( eventlogdir, 0755 );
349
350         /* get the path on disk */
351
352         tdbpath = elog_tdbname(ctx, logname);
353         if (!tdbpath) {
354                 return NULL;
355         }
356
357         DEBUG(7,("elog_open_tdb: Opening %s...(force_clear == %s)\n",
358                 tdbpath, force_clear?"True":"False" ));
359
360         /* the tdb wasn't already open or this is a forced clear open */
361
362         if ( !force_clear ) {
363
364                 tdb = tdb_open_log( tdbpath, 0, TDB_DEFAULT, O_RDWR , 0 );
365                 if ( tdb ) {
366                         vers_id = tdb_fetch_int32( tdb, EVT_VERSION );
367
368                         if ( vers_id != EVENTLOG_DATABASE_VERSION_V1 ) {
369                                 DEBUG(1,("elog_open_tdb: Invalid version [%d] on file [%s].\n",
370                                         vers_id, tdbpath));
371                                 tdb_close( tdb );
372                                 tdb = elog_init_tdb( tdbpath );
373                         }
374                 }
375         }
376         
377         if ( !tdb )
378                 tdb = elog_init_tdb( tdbpath );
379         
380         /* if we got a valid context, then add it to the list */
381         
382         if ( tdb ) {
383                 /* on a forced clear, just reset the tdb context if we already
384                    have an open entry in the list */
385
386                 if ( ptr ) {
387                         ptr->tdb = tdb;
388                         return ptr;
389                 }
390
391                 if ( !(tdb_node = TALLOC_ZERO_P( NULL, ELOG_TDB)) ) {
392                         DEBUG(0,("elog_open_tdb: talloc() failure!\n"));
393                         tdb_close( tdb );
394                         return NULL;
395                 }
396                 
397                 tdb_node->name = talloc_strdup( tdb_node, logname );
398                 tdb_node->tdb = tdb;
399                 tdb_node->ref_count = 1;
400                 
401                 DLIST_ADD( open_elog_list, tdb_node );
402         }
403
404         return tdb_node;
405 }
406
407 /*******************************************************************
408  Wrapper to handle reference counts to the tdb
409 *******************************************************************/
410
411 int elog_close_tdb( ELOG_TDB *etdb, bool force_close )
412 {
413         TDB_CONTEXT *tdb;
414
415         if ( !etdb )
416                 return 0;
417                 
418         etdb->ref_count--;
419         
420         SMB_ASSERT( etdb->ref_count >= 0 );
421
422         if ( etdb->ref_count == 0 ) {
423                 tdb = etdb->tdb;
424                 DLIST_REMOVE( open_elog_list, etdb );
425                 TALLOC_FREE( etdb );
426                 return tdb_close( tdb );
427         }
428         
429         if ( force_close ) {
430                 tdb = etdb->tdb;
431                 etdb->tdb = NULL;
432                 return tdb_close( tdb );
433         }
434
435         return 0;
436 }
437
438
439 /*******************************************************************
440  write an eventlog entry. Note that we have to lock, read next 
441  eventlog, increment, write, write the record, unlock 
442  
443  coming into this, ee has the eventlog record, and the auxilliary date 
444  (computer name, etc.) filled into the other structure. Before packing 
445  into a record, this routine will calc the appropriate padding, etc., 
446  and then blast out the record in a form that can be read back in
447 *******************************************************************/
448  
449 #define MARGIN 512
450
451 int write_eventlog_tdb( TDB_CONTEXT * the_tdb, Eventlog_entry * ee )
452 {
453         int32 next_record;
454         uint8 *packed_ee;
455         TALLOC_CTX *mem_ctx = NULL;
456         TDB_DATA kbuf, ebuf;
457         uint32 n_packed;
458
459         if ( !ee )
460                 return 0;
461
462         mem_ctx = talloc_init( "write_eventlog_tdb" );
463
464         if ( mem_ctx == NULL )
465                 return 0;
466
467         if ( !ee )
468                 return 0;
469         /* discard any entries that have bogus time, which usually indicates a bogus entry as well. */
470         if ( ee->record.time_generated == 0 )
471                 return 0;
472
473         /* todo - check for sanity in next_record */
474
475         fixup_eventlog_entry( ee );
476
477         if ( !can_write_to_eventlog( the_tdb, ee->record.length ) ) {
478                 DEBUG( 3, ( "Can't write to Eventlog, no room \n" ) );
479                 talloc_destroy( mem_ctx );
480                 return 0;
481         }
482
483         /* alloc mem for the packed version */
484         packed_ee = (uint8 *)TALLOC( mem_ctx, ee->record.length + MARGIN );
485         if ( !packed_ee ) {
486                 talloc_destroy( mem_ctx );
487                 return 0;
488         }
489
490         /* need to read the record number and insert it into the entry here */
491
492         /* lock */
493         tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
494         /* read */
495         next_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
496
497         n_packed =
498                 tdb_pack( (uint8 *)packed_ee, ee->record.length + MARGIN,
499                           "ddddddwwwwddddddBBdBBBd", ee->record.length,
500                           ee->record.reserved1, next_record,
501                           ee->record.time_generated, ee->record.time_written,
502                           ee->record.event_id, ee->record.event_type,
503                           ee->record.num_strings, ee->record.event_category,
504                           ee->record.reserved2,
505                           ee->record.closing_record_number,
506                           ee->record.string_offset,
507                           ee->record.user_sid_length,
508                           ee->record.user_sid_offset, ee->record.data_length,
509                           ee->record.data_offset,
510                           ee->data_record.source_name_len,
511                           ee->data_record.source_name,
512                           ee->data_record.computer_name_len,
513                           ee->data_record.computer_name,
514                           ee->data_record.sid_padding,
515                           ee->record.user_sid_length, ee->data_record.sid,
516                           ee->data_record.strings_len,
517                           ee->data_record.strings,
518                           ee->data_record.user_data_len,
519                           ee->data_record.user_data,
520                           ee->data_record.data_padding );
521
522         /*DEBUG(3,("write_eventlog_tdb: packed into  %d\n",n_packed)); */
523
524         /* increment the record count */
525
526         kbuf.dsize = sizeof( int32 );
527         kbuf.dptr = (uint8 * ) & next_record;
528
529         ebuf.dsize = n_packed;
530         ebuf.dptr = (uint8 *)packed_ee;
531
532         if ( tdb_store( the_tdb, kbuf, ebuf, 0 ) ) {
533                 /* DEBUG(1,("write_eventlog_tdb: Can't write record %d to eventlog\n",next_record)); */
534                 tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
535                 talloc_destroy( mem_ctx );
536                 return 0;
537         }
538         next_record++;
539         tdb_store_int32( the_tdb, EVT_NEXT_RECORD, next_record );
540         tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
541         talloc_destroy( mem_ctx );
542         return ( next_record - 1 );
543 }
544
545 /*******************************************************************
546  calculate the correct fields etc for an eventlog entry
547 *******************************************************************/
548
549 void fixup_eventlog_entry( Eventlog_entry * ee )
550 {
551         /* fix up the eventlog entry structure as necessary */
552
553         ee->data_record.sid_padding =
554                 ( ( 4 -
555                     ( ( ee->data_record.source_name_len +
556                         ee->data_record.computer_name_len ) % 4 ) ) % 4 );
557         ee->data_record.data_padding =
558                 ( 4 -
559                   ( ( ee->data_record.strings_len +
560                       ee->data_record.user_data_len ) % 4 ) ) % 4;
561         ee->record.length = sizeof( Eventlog_record );
562         ee->record.length += ee->data_record.source_name_len;
563         ee->record.length += ee->data_record.computer_name_len;
564         if ( ee->record.user_sid_length == 0 ) {
565                 /* Should not pad to a DWORD boundary for writing out the sid if there is
566                    no SID, so just propagate the padding to pad the data */
567                 ee->data_record.data_padding += ee->data_record.sid_padding;
568                 ee->data_record.sid_padding = 0;
569         }
570         /* DEBUG(10, ("sid_padding is [%d].\n", ee->data_record.sid_padding)); */
571         /* DEBUG(10, ("data_padding is [%d].\n", ee->data_record.data_padding)); */
572
573         ee->record.length += ee->data_record.sid_padding;
574         ee->record.length += ee->record.user_sid_length;
575         ee->record.length += ee->data_record.strings_len;
576         ee->record.length += ee->data_record.user_data_len;
577         ee->record.length += ee->data_record.data_padding;
578         /* need another copy of length at the end of the data */
579         ee->record.length += sizeof( ee->record.length );
580 }
581
582 /********************************************************************
583  Note that it's a pretty good idea to initialize the Eventlog_entry 
584  structure to zero's before calling parse_logentry on an batch of 
585  lines that may resolve to a record.  ALSO, it's a good idea to 
586  remove any linefeeds (that's EOL to you and me) on the lines 
587  going in.
588 ********************************************************************/
589
590 bool parse_logentry( char *line, Eventlog_entry * entry, bool * eor )
591 {
592         TALLOC_CTX *ctx = talloc_tos();
593         char *start = NULL, *stop = NULL;
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                 stop++;
660                 while ( isspace( stop[0] ) ) {
661                         stop++;
662                 }
663                 entry->data_record.source_name_len = rpcstr_push_talloc(ctx,
664                                 &entry->data_record.source_name,
665                                 stop);
666                 if (entry->data_record.source_name_len == (uint32_t)-1 ||
667                                 entry->data_record.source_name == NULL) {
668                         return false;
669                 }
670         } else if ( 0 == strncmp( start, "SRN", stop - start ) ) {
671                 stop++;
672                 while ( isspace( stop[0] ) ) {
673                         stop++;
674                 }
675                 entry->data_record.computer_name_len = rpcstr_push_talloc(ctx,
676                                 &entry->data_record.computer_name,
677                                 stop);
678                 if (entry->data_record.computer_name_len == (uint32_t)-1 ||
679                                 entry->data_record.computer_name == NULL) {
680                         return false;
681                 }
682         } else if ( 0 == strncmp( start, "SID", stop - start ) ) {
683                 stop++;
684                 while ( isspace( stop[0] ) ) {
685                         stop++;
686                 }
687                 entry->record.user_sid_length = rpcstr_push_talloc(ctx,
688                                 &entry->data_record.sid,
689                                 stop);
690                 if (entry->record.user_sid_length == (uint32_t)-1 ||
691                                 entry->data_record.sid == NULL) {
692                         return false;
693                 }
694         } else if ( 0 == strncmp( start, "STR", stop - start ) ) {
695                 smb_ucs2_t *temp = NULL;
696                 size_t tmp_len;
697                 uint32_t old_len;
698                 /* skip past initial ":" */
699                 stop++;
700                 /* now skip any other leading whitespace */
701                 while ( isspace(stop[0])) {
702                         stop++;
703                 }
704                 tmp_len = rpcstr_push_talloc(ctx,
705                                                 &temp,
706                                                 stop);
707                 if (tmp_len == (size_t)-1 || !temp) {
708                         return false;
709                 }
710                 old_len = entry->data_record.strings_len;
711                 entry->data_record.strings = (smb_ucs2_t *)TALLOC_REALLOC_ARRAY(ctx,
712                                                 entry->data_record.strings,
713                                                 char,
714                                                 old_len + tmp_len);
715                 if (!entry->data_record.strings) {
716                         return false;
717                 }
718                 memcpy(entry->data_record.strings + old_len,
719                                 temp,
720                                 tmp_len);
721                 entry->data_record.strings_len += tmp_len;
722                 entry->record.num_strings++;
723         } else if ( 0 == strncmp( start, "DAT", stop - start ) ) {
724                 /* skip past initial ":" */
725                 stop++;
726                 /* now skip any other leading whitespace */
727                 while ( isspace( stop[0] ) ) {
728                         stop++;
729                 }
730                 entry->data_record.user_data_len = strlen(stop);
731                 entry->data_record.user_data = talloc_strdup(ctx,
732                                                 stop);
733                 if (!entry->data_record.user_data) {
734                         return false;
735                 }
736         } else {
737                 /* some other eventlog entry -- not implemented, so dropping on the floor */
738                 DEBUG( 10, ( "Unknown entry [%s]. Ignoring.\n", line ) );
739                 /* For now return true so that we can keep on parsing this mess. Eventually
740                    we will return False here. */
741                 return true;
742         }
743         return true;
744 }