~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/lib/eventlog/eventlog.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 *  Copyright (C) Guenther Deschner          2009.
 
8
 *
 
9
 *  This program is free software; you can redistribute it and/or modify
 
10
 *  it under the terms of the GNU General Public License as published by
 
11
 *  the Free Software Foundation; either version 3 of the License, or
 
12
 *  (at your option) any later version.
 
13
 *
 
14
 *  This program is distributed in the hope that it will be useful,
 
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 *  GNU General Public License for more details.
 
18
 *
 
19
 *  You should have received a copy of the GNU General Public License
 
20
 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
 
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, 0660 );
 
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(TALLOC_CTX *ctx, const char *name )
 
67
{
 
68
        char *path = talloc_asprintf(ctx, "%s/%s.tdb",
 
69
                        state_path("eventlog"),
 
70
                        name);
 
71
        if (!path) {
 
72
                return NULL;
 
73
        }
 
74
        strlower_m(path);
 
75
        return path;
 
76
}
 
77
 
 
78
 
 
79
/********************************************************************
 
80
 this function is used to count up the number of bytes in a
 
81
 particular TDB
 
82
********************************************************************/
 
83
 
 
84
struct trav_size_struct {
 
85
        int size;
 
86
        int rec_count;
 
87
};
 
88
 
 
89
static int eventlog_tdb_size_fn( TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data,
 
90
                          void *state )
 
91
{
 
92
        struct trav_size_struct  *tsize = (struct trav_size_struct *)state;
 
93
 
 
94
        tsize->size += data.dsize;
 
95
        tsize->rec_count++;
 
96
 
 
97
        return 0;
 
98
}
 
99
 
 
100
/********************************************************************
 
101
 returns the size of the eventlog, and if MaxSize is a non-null
 
102
 ptr, puts the MaxSize there. This is purely a way not to have yet
 
103
 another function that solely reads the maxsize of the eventlog.
 
104
 Yeah, that's it.
 
105
********************************************************************/
 
106
 
 
107
int elog_tdb_size( TDB_CONTEXT * tdb, int *MaxSize, int *Retention )
 
108
{
 
109
        struct trav_size_struct tsize;
 
110
 
 
111
        if ( !tdb )
 
112
                return 0;
 
113
 
 
114
        ZERO_STRUCT( tsize );
 
115
 
 
116
        tdb_traverse( tdb, eventlog_tdb_size_fn, &tsize );
 
117
 
 
118
        if ( MaxSize != NULL ) {
 
119
                *MaxSize = tdb_fetch_int32( tdb, EVT_MAXSIZE );
 
120
        }
 
121
 
 
122
        if ( Retention != NULL ) {
 
123
                *Retention = tdb_fetch_int32( tdb, EVT_RETENTION );
 
124
        }
 
125
 
 
126
        DEBUG( 1,
 
127
               ( "eventlog size: [%d] for [%d] records\n", tsize.size,
 
128
                 tsize.rec_count ) );
 
129
        return tsize.size;
 
130
}
 
131
 
 
132
/********************************************************************
 
133
 Discard early event logs until we have enough for 'needed' bytes...
 
134
 NO checking done beforehand to see that we actually need to do
 
135
 this, and it's going to pluck records one-by-one. So, it's best
 
136
 to determine that this needs to be done before doing it.
 
137
 
 
138
 Setting whack_by_date to True indicates that eventlogs falling
 
139
 outside of the retention range need to go...
 
140
 
 
141
 return True if we made enough room to accommodate needed bytes
 
142
********************************************************************/
 
143
 
 
144
static bool make_way_for_eventlogs( TDB_CONTEXT * the_tdb, int32_t needed,
 
145
                                    bool whack_by_date )
 
146
{
 
147
        int32_t start_record, i, new_start;
 
148
        int32_t end_record;
 
149
        int32_t reclen, tresv1, trecnum, timegen, timewr;
 
150
        int nbytes, len, Retention, MaxSize;
 
151
        TDB_DATA key, ret;
 
152
        time_t current_time, exp_time;
 
153
 
 
154
        /* discard some eventlogs */
 
155
 
 
156
        /* read eventlogs from oldest_entry -- there can't be any discontinuity in recnos,
 
157
           although records not necessarily guaranteed to have successive times */
 
158
        /* */
 
159
 
 
160
        /* lock */
 
161
        tdb_lock_bystring_with_timeout( the_tdb, EVT_NEXT_RECORD, 1 );
 
162
        /* read */
 
163
        end_record = tdb_fetch_int32( the_tdb, EVT_NEXT_RECORD );
 
164
        start_record = tdb_fetch_int32( the_tdb, EVT_OLDEST_ENTRY );
 
165
        Retention = tdb_fetch_int32( the_tdb, EVT_RETENTION );
 
166
        MaxSize = tdb_fetch_int32( the_tdb, EVT_MAXSIZE );
 
167
 
 
168
        time( &current_time );
 
169
 
 
170
        /* calculate ... */
 
171
        exp_time = current_time - Retention;    /* discard older than exp_time */
 
172
 
 
173
        /* todo - check for sanity in next_record */
 
174
        nbytes = 0;
 
175
 
 
176
        DEBUG( 3,
 
177
               ( "MaxSize [%d] Retention [%d] Current Time [%u]  exp_time [%u]\n",
 
178
                 MaxSize, Retention, (unsigned int)current_time, (unsigned int)exp_time ) );
 
179
        DEBUG( 3,
 
180
               ( "Start Record [%u] End Record [%u]\n",
 
181
                (unsigned int)start_record,
 
182
                (unsigned int)end_record ));
 
183
 
 
184
        for ( i = start_record; i < end_record; i++ ) {
 
185
                /* read a record, add the amt to nbytes */
 
186
                key.dsize = sizeof(int32_t);
 
187
                key.dptr = (unsigned char *)&i;
 
188
                ret = tdb_fetch( the_tdb, key );
 
189
                if ( ret.dsize == 0 ) {
 
190
                        DEBUG( 8,
 
191
                               ( "Can't find a record for the key, record [%d]\n",
 
192
                                 i ) );
 
193
                        tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
 
194
                        return False;
 
195
                }
 
196
                nbytes += ret.dsize;    /* note this includes overhead */
 
197
 
 
198
                len = tdb_unpack( ret.dptr, ret.dsize, "ddddd", &reclen,
 
199
                                  &tresv1, &trecnum, &timegen, &timewr );
 
200
                if (len == -1) {
 
201
                        DEBUG( 10,("make_way_for_eventlogs: tdb_unpack failed.\n"));
 
202
                        tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
 
203
                        SAFE_FREE( ret.dptr );
 
204
                        return False;
 
205
                }
 
206
 
 
207
                DEBUG( 8,
 
208
                       ( "read record %u, record size is [%d], total so far [%d]\n",
 
209
                         (unsigned int)i, reclen, nbytes ) );
 
210
 
 
211
                SAFE_FREE( ret.dptr );
 
212
 
 
213
                /* note that other servers may just stop writing records when the size limit
 
214
                   is reached, and there are no records older than 'retention'. This doesn't
 
215
                   like a very useful thing to do, so instead we whack (as in sleeps with the
 
216
                   fishes) just enough records to fit the what we need.  This behavior could
 
217
                   be changed to 'match', if the need arises. */
 
218
 
 
219
                if ( !whack_by_date && ( nbytes >= needed ) )
 
220
                        break;  /* done */
 
221
                if ( whack_by_date && ( timegen >= exp_time ) )
 
222
                        break;  /* done */
 
223
        }
 
224
 
 
225
        DEBUG( 3,
 
226
               ( "nbytes [%d] needed [%d] start_record is [%u], should be set to [%u]\n",
 
227
                 nbytes, needed, (unsigned int)start_record, (unsigned int)i ) );
 
228
        /* todo - remove eventlog entries here and set starting record to start_record... */
 
229
        new_start = i;
 
230
        if ( start_record != new_start ) {
 
231
                for ( i = start_record; i < new_start; i++ ) {
 
232
                        key.dsize = sizeof(int32_t);
 
233
                        key.dptr = (unsigned char *)&i;
 
234
                        tdb_delete( the_tdb, key );
 
235
                }
 
236
 
 
237
                tdb_store_int32( the_tdb, EVT_OLDEST_ENTRY, new_start );
 
238
        }
 
239
        tdb_unlock_bystring( the_tdb, EVT_NEXT_RECORD );
 
240
        return True;
 
241
}
 
242
 
 
243
/********************************************************************
 
244
  some hygiene for an eventlog - see how big it is, and then
 
245
  calculate how many bytes we need to remove
 
246
********************************************************************/
 
247
 
 
248
bool prune_eventlog( TDB_CONTEXT * tdb )
 
249
{
 
250
        int MaxSize, Retention, CalcdSize;
 
251
 
 
252
        if ( !tdb ) {
 
253
                DEBUG( 4, ( "No eventlog tdb handle\n" ) );
 
254
                return False;
 
255
        }
 
256
 
 
257
        CalcdSize = elog_tdb_size( tdb, &MaxSize, &Retention );
 
258
        DEBUG( 3,
 
259
               ( "Calculated size [%d] MaxSize [%d]\n", CalcdSize,
 
260
                 MaxSize ) );
 
261
 
 
262
        if ( CalcdSize > MaxSize ) {
 
263
                return make_way_for_eventlogs( tdb, CalcdSize - MaxSize,
 
264
                                               False );
 
265
        }
 
266
 
 
267
        return make_way_for_eventlogs( tdb, 0, True );
 
268
}
 
269
 
 
270
/********************************************************************
 
271
********************************************************************/
 
272
 
 
273
static bool can_write_to_eventlog( TDB_CONTEXT * tdb, int32_t needed )
 
274
{
 
275
        int calcd_size;
 
276
        int MaxSize, Retention;
 
277
 
 
278
        /* see if we can write to the eventlog -- do a policy enforcement */
 
279
        if ( !tdb )
 
280
                return False;   /* tdb is null, so we can't write to it */
 
281
 
 
282
 
 
283
        if ( needed < 0 )
 
284
                return False;
 
285
        MaxSize = 0;
 
286
        Retention = 0;
 
287
 
 
288
        calcd_size = elog_tdb_size( tdb, &MaxSize, &Retention );
 
289
 
 
290
        if ( calcd_size <= MaxSize )
 
291
                return True;    /* you betcha */
 
292
        if ( calcd_size + needed < MaxSize )
 
293
                return True;
 
294
 
 
295
        if ( Retention == 0xffffffff ) {
 
296
                return False;   /* see msdn - we can't write no room, discard */
 
297
        }
 
298
        /*
 
299
           note don't have to test, but always good to show intent, in case changes needed
 
300
           later
 
301
         */
 
302
 
 
303
        if ( Retention == 0x00000000 ) {
 
304
                /* discard record(s) */
 
305
                /* todo  - decide when to remove a bunch vs. just what we need... */
 
306
                return make_way_for_eventlogs( tdb, calcd_size - MaxSize,
 
307
                                               True );
 
308
        }
 
309
 
 
310
        return make_way_for_eventlogs( tdb, calcd_size - MaxSize, False );
 
311
}
 
312
 
 
313
/*******************************************************************
 
314
*******************************************************************/
 
315
 
 
316
ELOG_TDB *elog_open_tdb( const char *logname, bool force_clear, bool read_only )
 
317
{
 
318
        TDB_CONTEXT *tdb = NULL;
 
319
        uint32_t vers_id;
 
320
        ELOG_TDB *ptr;
 
321
        char *tdbpath = NULL;
 
322
        ELOG_TDB *tdb_node = NULL;
 
323
        char *eventlogdir;
 
324
        TALLOC_CTX *ctx = talloc_tos();
 
325
 
 
326
        /* check for invalid options */
 
327
 
 
328
        if (force_clear && read_only) {
 
329
                DEBUG(1,("elog_open_tdb: Invalid flags\n"));
 
330
                return NULL;
 
331
        }
 
332
 
 
333
        /* first see if we have an open context */
 
334
 
 
335
        for ( ptr=open_elog_list; ptr; ptr=ptr->next ) {
 
336
                if ( strequal( ptr->name, logname ) ) {
 
337
                        ptr->ref_count++;
 
338
 
 
339
                        /* trick to alow clearing of the eventlog tdb.
 
340
                           The force_clear flag should imply that someone
 
341
                           has done a force close.  So make sure the tdb
 
342
                           is NULL.  If this is a normal open, then just
 
343
                           return the existing reference */
 
344
 
 
345
                        if ( force_clear ) {
 
346
                                SMB_ASSERT( ptr->tdb == NULL );
 
347
                                break;
 
348
                        }
 
349
                        else
 
350
                                return ptr;
 
351
                }
 
352
        }
 
353
 
 
354
        /* make sure that the eventlog dir exists */
 
355
 
 
356
        eventlogdir = state_path( "eventlog" );
 
357
        if ( !directory_exist( eventlogdir ) )
 
358
                mkdir( eventlogdir, 0755 );
 
359
 
 
360
        /* get the path on disk */
 
361
 
 
362
        tdbpath = elog_tdbname(ctx, logname);
 
363
        if (!tdbpath) {
 
364
                return NULL;
 
365
        }
 
366
 
 
367
        DEBUG(7,("elog_open_tdb: Opening %s...(force_clear == %s)\n",
 
368
                tdbpath, force_clear?"True":"False" ));
 
369
 
 
370
        /* the tdb wasn't already open or this is a forced clear open */
 
371
 
 
372
        if ( !force_clear ) {
 
373
 
 
374
                tdb = tdb_open_log( tdbpath, 0, TDB_DEFAULT, read_only ? O_RDONLY : O_RDWR , 0 );
 
375
                if ( tdb ) {
 
376
                        vers_id = tdb_fetch_int32( tdb, EVT_VERSION );
 
377
 
 
378
                        if ( vers_id != EVENTLOG_DATABASE_VERSION_V1 ) {
 
379
                                DEBUG(1,("elog_open_tdb: Invalid version [%d] on file [%s].\n",
 
380
                                        vers_id, tdbpath));
 
381
                                tdb_close( tdb );
 
382
                                tdb = elog_init_tdb( tdbpath );
 
383
                        }
 
384
                }
 
385
        }
 
386
 
 
387
        if ( !tdb )
 
388
                tdb = elog_init_tdb( tdbpath );
 
389
 
 
390
        /* if we got a valid context, then add it to the list */
 
391
 
 
392
        if ( tdb ) {
 
393
                /* on a forced clear, just reset the tdb context if we already
 
394
                   have an open entry in the list */
 
395
 
 
396
                if ( ptr ) {
 
397
                        ptr->tdb = tdb;
 
398
                        return ptr;
 
399
                }
 
400
 
 
401
                if ( !(tdb_node = TALLOC_ZERO_P( NULL, ELOG_TDB)) ) {
 
402
                        DEBUG(0,("elog_open_tdb: talloc() failure!\n"));
 
403
                        tdb_close( tdb );
 
404
                        return NULL;
 
405
                }
 
406
 
 
407
                tdb_node->name = talloc_strdup( tdb_node, logname );
 
408
                tdb_node->tdb = tdb;
 
409
                tdb_node->ref_count = 1;
 
410
 
 
411
                DLIST_ADD( open_elog_list, tdb_node );
 
412
        }
 
413
 
 
414
        return tdb_node;
 
415
}
 
416
 
 
417
/*******************************************************************
 
418
 Wrapper to handle reference counts to the tdb
 
419
*******************************************************************/
 
420
 
 
421
int elog_close_tdb( ELOG_TDB *etdb, bool force_close )
 
422
{
 
423
        TDB_CONTEXT *tdb;
 
424
 
 
425
        if ( !etdb )
 
426
                return 0;
 
427
 
 
428
        etdb->ref_count--;
 
429
 
 
430
        SMB_ASSERT( etdb->ref_count >= 0 );
 
431
 
 
432
        if ( etdb->ref_count == 0 ) {
 
433
                tdb = etdb->tdb;
 
434
                DLIST_REMOVE( open_elog_list, etdb );
 
435
                TALLOC_FREE( etdb );
 
436
                return tdb_close( tdb );
 
437
        }
 
438
 
 
439
        if ( force_close ) {
 
440
                tdb = etdb->tdb;
 
441
                etdb->tdb = NULL;
 
442
                return tdb_close( tdb );
 
443
        }
 
444
 
 
445
        return 0;
 
446
}
 
447
 
 
448
/********************************************************************
 
449
 Note that it's a pretty good idea to initialize the Eventlog_entry
 
450
 structure to zero's before calling parse_logentry on an batch of
 
451
 lines that may resolve to a record.  ALSO, it's a good idea to
 
452
 remove any linefeeds (that's EOL to you and me) on the lines
 
453
 going in.
 
454
********************************************************************/
 
455
 
 
456
bool parse_logentry( TALLOC_CTX *mem_ctx, char *line, struct eventlog_Record_tdb *entry, bool * eor )
 
457
{
 
458
        char *start = NULL, *stop = NULL;
 
459
 
 
460
        start = line;
 
461
 
 
462
        /* empty line signyfiying record delimeter, or we're at the end of the buffer */
 
463
        if ( start == NULL || strlen( start ) == 0 ) {
 
464
                DEBUG( 6,
 
465
                       ( "parse_logentry: found end-of-record indicator.\n" ) );
 
466
                *eor = True;
 
467
                return True;
 
468
        }
 
469
        if ( !( stop = strchr( line, ':' ) ) ) {
 
470
                return False;
 
471
        }
 
472
 
 
473
        DEBUG( 6, ( "parse_logentry: trying to parse [%s].\n", line ) );
 
474
 
 
475
        if ( 0 == strncmp( start, "LEN", stop - start ) ) {
 
476
                /* This will get recomputed later anyway -- probably not necessary */
 
477
                entry->size = atoi( stop + 1 );
 
478
        } else if ( 0 == strncmp( start, "RS1", stop - start ) ) {
 
479
                /* For now all these reserved entries seem to have the same value,
 
480
                   which can be hardcoded to int(1699505740) for now */
 
481
                entry->reserved = talloc_strdup(mem_ctx, "eLfL");
 
482
        } else if ( 0 == strncmp( start, "RCN", stop - start ) ) {
 
483
                entry->record_number = atoi( stop + 1 );
 
484
        } else if ( 0 == strncmp( start, "TMG", stop - start ) ) {
 
485
                entry->time_generated = atoi( stop + 1 );
 
486
        } else if ( 0 == strncmp( start, "TMW", stop - start ) ) {
 
487
                entry->time_written = atoi( stop + 1 );
 
488
        } else if ( 0 == strncmp( start, "EID", stop - start ) ) {
 
489
                entry->event_id = atoi( stop + 1 );
 
490
        } else if ( 0 == strncmp( start, "ETP", stop - start ) ) {
 
491
                if ( strstr( start, "ERROR" ) ) {
 
492
                        entry->event_type = EVENTLOG_ERROR_TYPE;
 
493
                } else if ( strstr( start, "WARNING" ) ) {
 
494
                        entry->event_type = EVENTLOG_WARNING_TYPE;
 
495
                } else if ( strstr( start, "INFO" ) ) {
 
496
                        entry->event_type = EVENTLOG_INFORMATION_TYPE;
 
497
                } else if ( strstr( start, "AUDIT_SUCCESS" ) ) {
 
498
                        entry->event_type = EVENTLOG_AUDIT_SUCCESS;
 
499
                } else if ( strstr( start, "AUDIT_FAILURE" ) ) {
 
500
                        entry->event_type = EVENTLOG_AUDIT_FAILURE;
 
501
                } else if ( strstr( start, "SUCCESS" ) ) {
 
502
                        entry->event_type = EVENTLOG_SUCCESS;
 
503
                } else {
 
504
                        /* some other eventlog type -- currently not defined in MSDN docs, so error out */
 
505
                        return False;
 
506
                }
 
507
        }
 
508
 
 
509
/*
 
510
  else if(0 == strncmp(start, "NST", stop - start))
 
511
  {
 
512
  entry->num_of_strings = atoi(stop + 1);
 
513
  }
 
514
*/
 
515
        else if ( 0 == strncmp( start, "ECT", stop - start ) ) {
 
516
                entry->event_category = atoi( stop + 1 );
 
517
        } else if ( 0 == strncmp( start, "RS2", stop - start ) ) {
 
518
                entry->reserved_flags = atoi( stop + 1 );
 
519
        } else if ( 0 == strncmp( start, "CRN", stop - start ) ) {
 
520
                entry->closing_record_number = atoi( stop + 1 );
 
521
        } else if ( 0 == strncmp( start, "USL", stop - start ) ) {
 
522
                entry->sid_length = atoi( stop + 1 );
 
523
        } else if ( 0 == strncmp( start, "SRC", stop - start ) ) {
 
524
                stop++;
 
525
                while ( isspace( stop[0] ) ) {
 
526
                        stop++;
 
527
                }
 
528
                entry->source_name_len = strlen_m_term(stop);
 
529
                entry->source_name = talloc_strdup(mem_ctx, stop);
 
530
                if (entry->source_name_len == (uint32_t)-1 ||
 
531
                                entry->source_name == NULL) {
 
532
                        return false;
 
533
                }
 
534
        } else if ( 0 == strncmp( start, "SRN", stop - start ) ) {
 
535
                stop++;
 
536
                while ( isspace( stop[0] ) ) {
 
537
                        stop++;
 
538
                }
 
539
                entry->computer_name_len = strlen_m_term(stop);
 
540
                entry->computer_name = talloc_strdup(mem_ctx, stop);
 
541
                if (entry->computer_name_len == (uint32_t)-1 ||
 
542
                                entry->computer_name == NULL) {
 
543
                        return false;
 
544
                }
 
545
        } else if ( 0 == strncmp( start, "SID", stop - start ) ) {
 
546
                smb_ucs2_t *dummy = NULL;
 
547
                stop++;
 
548
                while ( isspace( stop[0] ) ) {
 
549
                        stop++;
 
550
                }
 
551
                entry->sid_length = rpcstr_push_talloc(mem_ctx,
 
552
                                &dummy,
 
553
                                stop);
 
554
                if (entry->sid_length == (uint32_t)-1) {
 
555
                        return false;
 
556
                }
 
557
                entry->sid = data_blob_talloc(mem_ctx, dummy, entry->sid_length);
 
558
                if (entry->sid.data == NULL) {
 
559
                        return false;
 
560
                }
 
561
        } else if ( 0 == strncmp( start, "STR", stop - start ) ) {
 
562
                size_t tmp_len;
 
563
                int num_of_strings;
 
564
                /* skip past initial ":" */
 
565
                stop++;
 
566
                /* now skip any other leading whitespace */
 
567
                while ( isspace(stop[0])) {
 
568
                        stop++;
 
569
                }
 
570
                tmp_len = strlen_m_term(stop);
 
571
                if (tmp_len == (size_t)-1) {
 
572
                        return false;
 
573
                }
 
574
                num_of_strings = entry->num_of_strings;
 
575
                if (!add_string_to_array(mem_ctx, stop, &entry->strings,
 
576
                                         &num_of_strings)) {
 
577
                        return false;
 
578
                }
 
579
                if (num_of_strings > 0xffff) {
 
580
                        return false;
 
581
                }
 
582
                entry->num_of_strings = num_of_strings;
 
583
                entry->strings_len += tmp_len;
 
584
        } else if ( 0 == strncmp( start, "DAT", stop - start ) ) {
 
585
                /* skip past initial ":" */
 
586
                stop++;
 
587
                /* now skip any other leading whitespace */
 
588
                while ( isspace( stop[0] ) ) {
 
589
                        stop++;
 
590
                }
 
591
                entry->data_length = strlen_m(stop);
 
592
                entry->data = data_blob_talloc(mem_ctx, stop, entry->data_length);
 
593
                if (!entry->data.data) {
 
594
                        return false;
 
595
                }
 
596
        } else {
 
597
                /* some other eventlog entry -- not implemented, so dropping on the floor */
 
598
                DEBUG( 10, ( "Unknown entry [%s]. Ignoring.\n", line ) );
 
599
                /* For now return true so that we can keep on parsing this mess. Eventually
 
600
                   we will return False here. */
 
601
                return true;
 
602
        }
 
603
        return true;
 
604
}
 
605
 
 
606
/*******************************************************************
 
607
 calculate the correct fields etc for an eventlog entry
 
608
*******************************************************************/
 
609
 
 
610
size_t fixup_eventlog_record_tdb(struct eventlog_Record_tdb *r)
 
611
{
 
612
        size_t size = 56; /* static size of integers before buffers start */
 
613
 
 
614
        r->source_name_len = strlen_m_term(r->source_name) * 2;
 
615
        r->computer_name_len = strlen_m_term(r->computer_name) * 2;
 
616
        r->strings_len = ndr_size_string_array(r->strings,
 
617
                r->num_of_strings, LIBNDR_FLAG_STR_NULLTERM) * 2;
 
618
 
 
619
        /* fix up the eventlog entry structure as necessary */
 
620
        r->sid_padding = ( ( 4 - ( ( r->source_name_len + r->computer_name_len ) % 4 ) ) % 4 );
 
621
        r->padding =       ( 4 - ( ( r->strings_len + r->data_length ) % 4 ) ) % 4;
 
622
 
 
623
        if (r->sid_length == 0) {
 
624
                /* Should not pad to a DWORD boundary for writing out the sid if there is
 
625
                   no SID, so just propagate the padding to pad the data */
 
626
                r->padding += r->sid_padding;
 
627
                r->sid_padding = 0;
 
628
        }
 
629
 
 
630
        size += r->source_name_len;
 
631
        size += r->computer_name_len;
 
632
        size += r->sid_padding;
 
633
        size += r->sid_length;
 
634
        size += r->strings_len;
 
635
        size += r->data_length;
 
636
        size += r->padding;
 
637
        /* need another copy of length at the end of the data */
 
638
        size += sizeof(r->size);
 
639
 
 
640
        r->size = size;
 
641
 
 
642
        return size;
 
643
}
 
644
 
 
645
 
 
646
/********************************************************************
 
647
 ********************************************************************/
 
648
 
 
649
struct eventlog_Record_tdb *evlog_pull_record_tdb(TALLOC_CTX *mem_ctx,
 
650
                                                  TDB_CONTEXT *tdb,
 
651
                                                  uint32_t record_number)
 
652
{
 
653
        struct eventlog_Record_tdb *r;
 
654
        TDB_DATA data, key;
 
655
 
 
656
        int32_t srecno;
 
657
        enum ndr_err_code ndr_err;
 
658
        DATA_BLOB blob;
 
659
 
 
660
        srecno = record_number;
 
661
        key.dptr = (unsigned char *)&srecno;
 
662
        key.dsize = sizeof(int32_t);
 
663
 
 
664
        data = tdb_fetch(tdb, key);
 
665
        if (data.dsize == 0) {
 
666
                DEBUG(8,("evlog_pull_record_tdb: "
 
667
                        "Can't find a record for the key, record %d\n",
 
668
                        record_number));
 
669
                return NULL;
 
670
        }
 
671
 
 
672
        r = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
 
673
        if (!r) {
 
674
                goto done;
 
675
        }
 
676
 
 
677
        blob = data_blob_const(data.dptr, data.dsize);
 
678
 
 
679
        ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, r,
 
680
                           (ndr_pull_flags_fn_t)ndr_pull_eventlog_Record_tdb);
 
681
 
 
682
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
683
                DEBUG(10,("evlog_pull_record_tdb: failed to decode record %d\n",
 
684
                        record_number));
 
685
                TALLOC_FREE(r);
 
686
                goto done;
 
687
        }
 
688
 
 
689
        if (DEBUGLEVEL >= 10) {
 
690
                NDR_PRINT_DEBUG(eventlog_Record_tdb, r);
 
691
        }
 
692
 
 
693
        DEBUG(10,("evlog_pull_record_tdb: retrieved entry for record %d\n",
 
694
                record_number));
 
695
 done:
 
696
        SAFE_FREE(data.dptr);
 
697
 
 
698
        return r;
 
699
}
 
700
 
 
701
/********************************************************************
 
702
 ********************************************************************/
 
703
 
 
704
struct EVENTLOGRECORD *evlog_pull_record(TALLOC_CTX *mem_ctx,
 
705
                                         TDB_CONTEXT *tdb,
 
706
                                         uint32_t record_number)
 
707
{
 
708
        struct eventlog_Record_tdb *t;
 
709
        struct EVENTLOGRECORD *r;
 
710
        NTSTATUS status;
 
711
 
 
712
        r = talloc_zero(mem_ctx, struct EVENTLOGRECORD);
 
713
        if (!r) {
 
714
                return NULL;
 
715
        }
 
716
 
 
717
        t = evlog_pull_record_tdb(r, tdb, record_number);
 
718
        if (!t) {
 
719
                talloc_free(r);
 
720
                return NULL;
 
721
        }
 
722
 
 
723
        status = evlog_tdb_entry_to_evt_entry(r, t, r);
 
724
        if (!NT_STATUS_IS_OK(status)) {
 
725
                talloc_free(r);
 
726
                return NULL;
 
727
        }
 
728
 
 
729
        r->Length = r->Length2 = ndr_size_EVENTLOGRECORD(r, NULL, 0);
 
730
 
 
731
        return r;
 
732
}
 
733
 
 
734
/********************************************************************
 
735
 write an eventlog entry. Note that we have to lock, read next
 
736
 eventlog, increment, write, write the record, unlock
 
737
 
 
738
 coming into this, ee has the eventlog record, and the auxilliary date
 
739
 (computer name, etc.) filled into the other structure. Before packing
 
740
 into a record, this routine will calc the appropriate padding, etc.,
 
741
 and then blast out the record in a form that can be read back in
 
742
 ********************************************************************/
 
743
 
 
744
NTSTATUS evlog_push_record_tdb(TALLOC_CTX *mem_ctx,
 
745
                               TDB_CONTEXT *tdb,
 
746
                               struct eventlog_Record_tdb *r,
 
747
                               uint32_t *record_number)
 
748
{
 
749
        TDB_DATA kbuf, ebuf;
 
750
        DATA_BLOB blob;
 
751
        enum ndr_err_code ndr_err;
 
752
        int ret;
 
753
 
 
754
        if (!r) {
 
755
                return NT_STATUS_INVALID_PARAMETER;
 
756
        }
 
757
 
 
758
        if (!can_write_to_eventlog(tdb, r->size)) {
 
759
                return NT_STATUS_EVENTLOG_CANT_START;
 
760
        }
 
761
 
 
762
        /* need to read the record number and insert it into the entry here */
 
763
 
 
764
        /* lock */
 
765
        ret = tdb_lock_bystring_with_timeout(tdb, EVT_NEXT_RECORD, 1);
 
766
        if (ret == -1) {
 
767
                return NT_STATUS_LOCK_NOT_GRANTED;
 
768
        }
 
769
 
 
770
        /* read */
 
771
        r->record_number = tdb_fetch_int32(tdb, EVT_NEXT_RECORD);
 
772
 
 
773
        ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, r,
 
774
                      (ndr_push_flags_fn_t)ndr_push_eventlog_Record_tdb);
 
775
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
776
                tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
 
777
                return ndr_map_error2ntstatus(ndr_err);
 
778
        }
 
779
 
 
780
        /* increment the record count */
 
781
 
 
782
        kbuf.dsize = sizeof(int32_t);
 
783
        kbuf.dptr = (uint8_t *)&r->record_number;
 
784
 
 
785
        ebuf.dsize = blob.length;
 
786
        ebuf.dptr  = blob.data;
 
787
 
 
788
        ret = tdb_store(tdb, kbuf, ebuf, 0);
 
789
        if (ret == -1) {
 
790
                tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
 
791
                return NT_STATUS_EVENTLOG_FILE_CORRUPT;
 
792
        }
 
793
 
 
794
        ret = tdb_store_int32(tdb, EVT_NEXT_RECORD, r->record_number + 1);
 
795
        if (ret == -1) {
 
796
                tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
 
797
                return NT_STATUS_EVENTLOG_FILE_CORRUPT;
 
798
        }
 
799
        tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
 
800
 
 
801
        if (record_number) {
 
802
                *record_number = r->record_number;
 
803
        }
 
804
 
 
805
        return NT_STATUS_OK;
 
806
}
 
807
 
 
808
/********************************************************************
 
809
 ********************************************************************/
 
810
 
 
811
NTSTATUS evlog_push_record(TALLOC_CTX *mem_ctx,
 
812
                           TDB_CONTEXT *tdb,
 
813
                           struct EVENTLOGRECORD *r,
 
814
                           uint32_t *record_number)
 
815
{
 
816
        struct eventlog_Record_tdb *t;
 
817
        NTSTATUS status;
 
818
 
 
819
        t = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
 
820
        if (!t) {
 
821
                return NT_STATUS_NO_MEMORY;
 
822
        }
 
823
 
 
824
        status = evlog_evt_entry_to_tdb_entry(t, r, t);
 
825
        if (!NT_STATUS_IS_OK(status)) {
 
826
                talloc_free(t);
 
827
                return status;
 
828
        }
 
829
 
 
830
        status = evlog_push_record_tdb(mem_ctx, tdb, t, record_number);
 
831
        talloc_free(t);
 
832
 
 
833
        return status;
 
834
}
 
835
 
 
836
/********************************************************************
 
837
 ********************************************************************/
 
838
 
 
839
NTSTATUS evlog_evt_entry_to_tdb_entry(TALLOC_CTX *mem_ctx,
 
840
                                      const struct EVENTLOGRECORD *e,
 
841
                                      struct eventlog_Record_tdb *t)
 
842
{
 
843
        uint32_t i;
 
844
 
 
845
        ZERO_STRUCTP(t);
 
846
 
 
847
        t->size                         = e->Length;
 
848
        t->reserved                     = e->Reserved;
 
849
        t->record_number                = e->RecordNumber;
 
850
        t->time_generated               = e->TimeGenerated;
 
851
        t->time_written                 = e->TimeWritten;
 
852
        t->event_id                     = e->EventID;
 
853
        t->event_type                   = e->EventType;
 
854
        t->num_of_strings               = e->NumStrings;
 
855
        t->event_category               = e->EventCategory;
 
856
        t->reserved_flags               = e->ReservedFlags;
 
857
        t->closing_record_number        = e->ClosingRecordNumber;
 
858
 
 
859
        t->stringoffset                 = e->StringOffset;
 
860
        t->sid_length                   = e->UserSidLength;
 
861
        t->sid_offset                   = e->UserSidOffset;
 
862
        t->data_length                  = e->DataLength;
 
863
        t->data_offset                  = e->DataOffset;
 
864
 
 
865
        t->source_name_len              = 2 * strlen_m_term(e->SourceName);
 
866
        t->source_name                  = talloc_strdup(mem_ctx, e->SourceName);
 
867
        NT_STATUS_HAVE_NO_MEMORY(t->source_name);
 
868
 
 
869
        t->computer_name_len            = 2 * strlen_m_term(e->Computername);
 
870
        t->computer_name                = talloc_strdup(mem_ctx, e->Computername);
 
871
        NT_STATUS_HAVE_NO_MEMORY(t->computer_name);
 
872
 
 
873
        /* t->sid_padding; */
 
874
        if (e->UserSidLength > 0) {
 
875
                const char *sid_str = NULL;
 
876
                smb_ucs2_t *dummy = NULL;
 
877
                sid_str = sid_string_talloc(mem_ctx, &e->UserSid);
 
878
                t->sid_length = rpcstr_push_talloc(mem_ctx, &dummy, sid_str);
 
879
                if (t->sid_length == -1) {
 
880
                        return NT_STATUS_NO_MEMORY;
 
881
                }
 
882
                t->sid = data_blob_talloc(mem_ctx, (uint8_t *)dummy, t->sid_length);
 
883
                NT_STATUS_HAVE_NO_MEMORY(t->sid.data);
 
884
        }
 
885
 
 
886
        t->strings                      = talloc_array(mem_ctx, const char *, e->NumStrings);
 
887
        for (i=0; i < e->NumStrings; i++) {
 
888
                t->strings[i]           = talloc_strdup(t->strings, e->Strings[i]);
 
889
                NT_STATUS_HAVE_NO_MEMORY(t->strings[i]);
 
890
        }
 
891
 
 
892
        t->strings_len                  = 2 * ndr_size_string_array(t->strings, t->num_of_strings, LIBNDR_FLAG_STR_NULLTERM);
 
893
        t->data                         = data_blob_talloc(mem_ctx, e->Data, e->DataLength);
 
894
        /* t->padding                   = r->Pad; */
 
895
 
 
896
        return NT_STATUS_OK;
 
897
}
 
898
 
 
899
/********************************************************************
 
900
 ********************************************************************/
 
901
 
 
902
NTSTATUS evlog_tdb_entry_to_evt_entry(TALLOC_CTX *mem_ctx,
 
903
                                      const struct eventlog_Record_tdb *t,
 
904
                                      struct EVENTLOGRECORD *e)
 
905
{
 
906
        uint32_t i;
 
907
 
 
908
        ZERO_STRUCTP(e);
 
909
 
 
910
        e->Length               = t->size;
 
911
        e->Reserved             = t->reserved;
 
912
        e->RecordNumber         = t->record_number;
 
913
        e->TimeGenerated        = t->time_generated;
 
914
        e->TimeWritten          = t->time_written;
 
915
        e->EventID              = t->event_id;
 
916
        e->EventType            = t->event_type;
 
917
        e->NumStrings           = t->num_of_strings;
 
918
        e->EventCategory        = t->event_category;
 
919
        e->ReservedFlags        = t->reserved_flags;
 
920
        e->ClosingRecordNumber  = t->closing_record_number;
 
921
 
 
922
        e->StringOffset         = t->stringoffset;
 
923
        e->UserSidLength        = t->sid_length;
 
924
        e->UserSidOffset        = t->sid_offset;
 
925
        e->DataLength           = t->data_length;
 
926
        e->DataOffset           = t->data_offset;
 
927
 
 
928
        e->SourceName           = talloc_strdup(mem_ctx, t->source_name);
 
929
        NT_STATUS_HAVE_NO_MEMORY(e->SourceName);
 
930
 
 
931
        e->Computername         = talloc_strdup(mem_ctx, t->computer_name);
 
932
        NT_STATUS_HAVE_NO_MEMORY(e->Computername);
 
933
 
 
934
        if (t->sid_length > 0) {
 
935
                const char *sid_str = NULL;
 
936
                size_t len;
 
937
                if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
 
938
                                           t->sid.data, t->sid.length,
 
939
                                           (void **)&sid_str, &len, false)) {
 
940
                        return NT_STATUS_INVALID_SID;
 
941
                }
 
942
                if (len > 0) {
 
943
                        e->UserSid = *string_sid_talloc(mem_ctx, sid_str);
 
944
                }
 
945
        }
 
946
 
 
947
        e->Strings              = talloc_array(mem_ctx, const char *, t->num_of_strings);
 
948
        for (i=0; i < t->num_of_strings; i++) {
 
949
                e->Strings[i] = talloc_strdup(e->Strings, t->strings[i]);
 
950
                NT_STATUS_HAVE_NO_MEMORY(e->Strings[i]);
 
951
        }
 
952
 
 
953
        e->Data                 = (uint8_t *)talloc_memdup(mem_ctx, t->data.data, t->data_length);
 
954
        e->Pad                  = talloc_strdup(mem_ctx, "");
 
955
        NT_STATUS_HAVE_NO_MEMORY(e->Pad);
 
956
 
 
957
        e->Length2              = t->size;
 
958
 
 
959
        return NT_STATUS_OK;
 
960
}
 
961
 
 
962
/********************************************************************
 
963
 ********************************************************************/
 
964
 
 
965
NTSTATUS evlog_convert_tdb_to_evt(TALLOC_CTX *mem_ctx,
 
966
                                  ELOG_TDB *etdb,
 
967
                                  DATA_BLOB *blob_p,
 
968
                                  uint32_t *num_records_p)
 
969
{
 
970
        NTSTATUS status = NT_STATUS_OK;
 
971
        enum ndr_err_code ndr_err;
 
972
        DATA_BLOB blob;
 
973
        uint32_t num_records = 0;
 
974
        struct EVENTLOG_EVT_FILE evt;
 
975
        uint32_t count = 1;
 
976
        size_t endoffset = 0;
 
977
 
 
978
        ZERO_STRUCT(evt);
 
979
 
 
980
        while (1) {
 
981
 
 
982
                struct eventlog_Record_tdb *r;
 
983
                struct EVENTLOGRECORD e;
 
984
 
 
985
                r = evlog_pull_record_tdb(mem_ctx, etdb->tdb, count);
 
986
                if (!r) {
 
987
                        break;
 
988
                }
 
989
 
 
990
                status = evlog_tdb_entry_to_evt_entry(mem_ctx, r, &e);
 
991
                if (!NT_STATUS_IS_OK(status)) {
 
992
                        goto done;
 
993
                }
 
994
 
 
995
                endoffset += ndr_size_EVENTLOGRECORD(&e, NULL, 0);
 
996
 
 
997
                ADD_TO_ARRAY(mem_ctx, struct EVENTLOGRECORD, e, &evt.records, &num_records);
 
998
                count++;
 
999
        }
 
1000
 
 
1001
        evt.hdr.StartOffset             = 0x30;
 
1002
        evt.hdr.EndOffset               = evt.hdr.StartOffset + endoffset;
 
1003
        evt.hdr.CurrentRecordNumber     = count;
 
1004
        evt.hdr.OldestRecordNumber      = 1;
 
1005
        evt.hdr.MaxSize                 = tdb_fetch_int32(etdb->tdb, EVT_MAXSIZE);
 
1006
        evt.hdr.Flags                   = 0;
 
1007
        evt.hdr.Retention               = tdb_fetch_int32(etdb->tdb, EVT_RETENTION);
 
1008
 
 
1009
        if (DEBUGLEVEL >= 10) {
 
1010
                NDR_PRINT_DEBUG(EVENTLOGHEADER, &evt.hdr);
 
1011
        }
 
1012
 
 
1013
        evt.eof.BeginRecord             = 0x30;
 
1014
        evt.eof.EndRecord               = evt.hdr.StartOffset + endoffset;
 
1015
        evt.eof.CurrentRecordNumber     = evt.hdr.CurrentRecordNumber;
 
1016
        evt.eof.OldestRecordNumber      = evt.hdr.OldestRecordNumber;
 
1017
 
 
1018
        if (DEBUGLEVEL >= 10) {
 
1019
                NDR_PRINT_DEBUG(EVENTLOGEOF, &evt.eof);
 
1020
        }
 
1021
 
 
1022
        ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, &evt,
 
1023
                   (ndr_push_flags_fn_t)ndr_push_EVENTLOG_EVT_FILE);
 
1024
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
1025
                status = ndr_map_error2ntstatus(ndr_err);
 
1026
                goto done;
 
1027
        }
 
1028
 
 
1029
        *blob_p = blob;
 
1030
        *num_records_p = num_records;
 
1031
 
 
1032
 done:
 
1033
        return status;
 
1034
}