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