s3-eventlog: remove fixup_eventlog_entry.
[kai/samba-autobuild/.git] / source3 / rpc_server / srv_eventlog_lib.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  Eventlog utility  routines
4  *  Copyright (C) Marcin Krzysztof Porwit    2005,
5  *  Copyright (C) Brian Moran                2005.
6  *  Copyright (C) Gerald (Jerry) Carter      2005.
7  *  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                 entry->sid = data_blob_talloc(mem_ctx, dummy, entry->sid_length);
555                 if (entry->sid_length == (uint32_t)-1 ||
556                                 entry->sid.data == NULL) {
557                         return false;
558                 }
559         } else if ( 0 == strncmp( start, "STR", stop - start ) ) {
560                 size_t tmp_len;
561                 /* skip past initial ":" */
562                 stop++;
563                 /* now skip any other leading whitespace */
564                 while ( isspace(stop[0])) {
565                         stop++;
566                 }
567                 tmp_len = strlen_m_term(stop);
568                 if (tmp_len == (size_t)-1) {
569                         return false;
570                 }
571                 if (!add_string_to_array(mem_ctx, stop, &entry->strings,
572                                          (int *)&entry->num_of_strings)) {
573                         return false;
574                 }
575                 entry->strings_len += tmp_len;
576         } else if ( 0 == strncmp( start, "DAT", stop - start ) ) {
577                 /* skip past initial ":" */
578                 stop++;
579                 /* now skip any other leading whitespace */
580                 while ( isspace( stop[0] ) ) {
581                         stop++;
582                 }
583                 entry->data_length = strlen_m(stop);
584                 entry->data = data_blob_talloc(mem_ctx, stop, entry->data_length);
585                 if (!entry->data.data) {
586                         return false;
587                 }
588         } else {
589                 /* some other eventlog entry -- not implemented, so dropping on the floor */
590                 DEBUG( 10, ( "Unknown entry [%s]. Ignoring.\n", line ) );
591                 /* For now return true so that we can keep on parsing this mess. Eventually
592                    we will return False here. */
593                 return true;
594         }
595         return true;
596 }
597
598 /*******************************************************************
599  calculate the correct fields etc for an eventlog entry
600 *******************************************************************/
601
602 size_t fixup_eventlog_record_tdb(struct eventlog_Record_tdb *r)
603 {
604         size_t size = 56; /* static size of integers before buffers start */
605
606         r->source_name_len = strlen_m_term(r->source_name) * 2;
607         r->computer_name_len = strlen_m_term(r->computer_name) * 2;
608         r->strings_len = ndr_size_string_array(r->strings,
609                 r->num_of_strings, LIBNDR_FLAG_STR_NULLTERM) * 2;
610
611         /* fix up the eventlog entry structure as necessary */
612         r->sid_padding = ( ( 4 - ( ( r->source_name_len + r->computer_name_len ) % 4 ) ) % 4 );
613         r->padding =       ( 4 - ( ( r->strings_len + r->data_length ) % 4 ) ) % 4;
614
615         if (r->sid_length == 0) {
616                 /* Should not pad to a DWORD boundary for writing out the sid if there is
617                    no SID, so just propagate the padding to pad the data */
618                 r->padding += r->sid_padding;
619                 r->sid_padding = 0;
620         }
621
622         size += r->source_name_len;
623         size += r->computer_name_len;
624         size += r->sid_padding;
625         size += r->sid_length;
626         size += r->strings_len;
627         size += r->data_length;
628         size += r->padding;
629         /* need another copy of length at the end of the data */
630         size += sizeof(r->size);
631
632         r->size = size;
633
634         return size;
635 }
636
637
638 /********************************************************************
639  ********************************************************************/
640
641 struct eventlog_Record_tdb *evlog_pull_record_tdb(TALLOC_CTX *mem_ctx,
642                                                   TDB_CONTEXT *tdb,
643                                                   uint32_t record_number)
644 {
645         struct eventlog_Record_tdb *r;
646         TDB_DATA data, key;
647
648         int32_t srecno;
649         enum ndr_err_code ndr_err;
650         DATA_BLOB blob;
651
652         srecno = record_number;
653         key.dptr = (unsigned char *)&srecno;
654         key.dsize = sizeof(int32_t);
655
656         data = tdb_fetch(tdb, key);
657         if (data.dsize == 0) {
658                 DEBUG(8,("evlog_pull_record_tdb: "
659                         "Can't find a record for the key, record %d\n",
660                         record_number));
661                 return NULL;
662         }
663
664         r = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
665         if (!r) {
666                 goto done;
667         }
668
669         blob = data_blob_const(data.dptr, data.dsize);
670
671         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, r,
672                            (ndr_pull_flags_fn_t)ndr_pull_eventlog_Record_tdb);
673
674         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
675                 DEBUG(10,("evlog_pull_record_tdb: failed to decode record %d\n",
676                         record_number));
677                 TALLOC_FREE(r);
678                 goto done;
679         }
680
681         if (DEBUGLEVEL >= 10) {
682                 NDR_PRINT_DEBUG(eventlog_Record_tdb, r);
683         }
684
685         DEBUG(10,("evlog_pull_record_tdb: retrieved entry for record %d\n",
686                 record_number));
687  done:
688         SAFE_FREE(data.dptr);
689
690         return r;
691 }
692
693 /********************************************************************
694  ********************************************************************/
695
696 struct EVENTLOGRECORD *evlog_pull_record(TALLOC_CTX *mem_ctx,
697                                          TDB_CONTEXT *tdb,
698                                          uint32_t record_number)
699 {
700         struct eventlog_Record_tdb *t;
701         struct EVENTLOGRECORD *r;
702         NTSTATUS status;
703
704         r = talloc_zero(mem_ctx, struct EVENTLOGRECORD);
705         if (!r) {
706                 return NULL;
707         }
708
709         t = evlog_pull_record_tdb(r, tdb, record_number);
710         if (!t) {
711                 talloc_free(r);
712                 return NULL;
713         }
714
715         status = evlog_tdb_entry_to_evt_entry(r, t, r);
716         if (!NT_STATUS_IS_OK(status)) {
717                 talloc_free(r);
718                 return NULL;
719         }
720
721         r->Length = r->Length2 = ndr_size_EVENTLOGRECORD(r, NULL, 0);
722
723         return r;
724 }
725
726 /********************************************************************
727  write an eventlog entry. Note that we have to lock, read next
728  eventlog, increment, write, write the record, unlock
729
730  coming into this, ee has the eventlog record, and the auxilliary date
731  (computer name, etc.) filled into the other structure. Before packing
732  into a record, this routine will calc the appropriate padding, etc.,
733  and then blast out the record in a form that can be read back in
734  ********************************************************************/
735
736 NTSTATUS evlog_push_record_tdb(TALLOC_CTX *mem_ctx,
737                                TDB_CONTEXT *tdb,
738                                struct eventlog_Record_tdb *r,
739                                uint32_t *record_number)
740 {
741         TDB_DATA kbuf, ebuf;
742         DATA_BLOB blob;
743         enum ndr_err_code ndr_err;
744         int ret;
745
746         if (!r) {
747                 return NT_STATUS_INVALID_PARAMETER;
748         }
749
750         if (!can_write_to_eventlog(tdb, r->size)) {
751                 return NT_STATUS_EVENTLOG_CANT_START;
752         }
753
754         /* need to read the record number and insert it into the entry here */
755
756         /* lock */
757         ret = tdb_lock_bystring_with_timeout(tdb, EVT_NEXT_RECORD, 1);
758         if (ret == -1) {
759                 return NT_STATUS_LOCK_NOT_GRANTED;
760         }
761
762         /* read */
763         r->record_number = tdb_fetch_int32(tdb, EVT_NEXT_RECORD);
764
765         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, r,
766                       (ndr_push_flags_fn_t)ndr_push_eventlog_Record_tdb);
767         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
768                 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
769                 return ndr_map_error2ntstatus(ndr_err);
770         }
771
772         /* increment the record count */
773
774         kbuf.dsize = sizeof(int32_t);
775         kbuf.dptr = (uint8_t *)&r->record_number;
776
777         ebuf.dsize = blob.length;
778         ebuf.dptr  = blob.data;
779
780         ret = tdb_store(tdb, kbuf, ebuf, 0);
781         if (ret == -1) {
782                 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
783                 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
784         }
785
786         ret = tdb_store_int32(tdb, EVT_NEXT_RECORD, r->record_number + 1);
787         if (ret == -1) {
788                 tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
789                 return NT_STATUS_EVENTLOG_FILE_CORRUPT;
790         }
791         tdb_unlock_bystring(tdb, EVT_NEXT_RECORD);
792
793         if (record_number) {
794                 *record_number = r->record_number;
795         }
796
797         return NT_STATUS_OK;
798 }
799
800 /********************************************************************
801  ********************************************************************/
802
803 NTSTATUS evlog_push_record(TALLOC_CTX *mem_ctx,
804                            TDB_CONTEXT *tdb,
805                            struct EVENTLOGRECORD *r,
806                            uint32_t *record_number)
807 {
808         struct eventlog_Record_tdb *t;
809         NTSTATUS status;
810
811         t = talloc_zero(mem_ctx, struct eventlog_Record_tdb);
812         if (!t) {
813                 return NT_STATUS_NO_MEMORY;
814         }
815
816         status = evlog_evt_entry_to_tdb_entry(t, r, t);
817         if (!NT_STATUS_IS_OK(status)) {
818                 talloc_free(t);
819                 return status;
820         }
821
822         status = evlog_push_record_tdb(mem_ctx, tdb, t, record_number);
823         talloc_free(t);
824
825         return status;
826 }
827
828 /********************************************************************
829  ********************************************************************/
830
831 NTSTATUS evlog_evt_entry_to_tdb_entry(TALLOC_CTX *mem_ctx,
832                                       const struct EVENTLOGRECORD *e,
833                                       struct eventlog_Record_tdb *t)
834 {
835         uint32_t i;
836
837         ZERO_STRUCTP(t);
838
839         t->size                         = e->Length;
840         t->reserved                     = e->Reserved;
841         t->record_number                = e->RecordNumber;
842         t->time_generated               = e->TimeGenerated;
843         t->time_written                 = e->TimeWritten;
844         t->event_id                     = e->EventID;
845         t->event_type                   = e->EventType;
846         t->num_of_strings               = e->NumStrings;
847         t->event_category               = e->EventCategory;
848         t->reserved_flags               = e->ReservedFlags;
849         t->closing_record_number        = e->ClosingRecordNumber;
850
851         t->stringoffset                 = e->StringOffset;
852         t->sid_length                   = e->UserSidLength;
853         t->sid_offset                   = e->UserSidOffset;
854         t->data_length                  = e->DataLength;
855         t->data_offset                  = e->DataOffset;
856
857         t->source_name_len              = 2 * strlen_m_term(e->SourceName);
858         t->source_name                  = talloc_strdup(mem_ctx, e->SourceName);
859         NT_STATUS_HAVE_NO_MEMORY(t->source_name);
860
861         t->computer_name_len            = 2 * strlen_m_term(e->Computername);
862         t->computer_name                = talloc_strdup(mem_ctx, e->Computername);
863         NT_STATUS_HAVE_NO_MEMORY(t->computer_name);
864
865         /* t->sid_padding; */
866         if (e->UserSidLength > 0) {
867                 const char *sid_str = NULL;
868                 smb_ucs2_t *dummy = NULL;
869                 sid_str = sid_string_talloc(mem_ctx, &e->UserSid);
870                 t->sid_length = rpcstr_push_talloc(mem_ctx, &dummy, sid_str);
871                 if (t->sid_length == -1) {
872                         return NT_STATUS_NO_MEMORY;
873                 }
874                 t->sid = data_blob_talloc(mem_ctx, (uint8_t *)dummy, t->sid_length);
875                 NT_STATUS_HAVE_NO_MEMORY(t->sid.data);
876         }
877
878         t->strings                      = talloc_array(mem_ctx, const char *, e->NumStrings);
879         for (i=0; i < e->NumStrings; i++) {
880                 t->strings[i]           = talloc_strdup(t->strings, e->Strings[i]);
881                 NT_STATUS_HAVE_NO_MEMORY(t->strings[i]);
882         }
883
884         t->strings_len                  = 2 * ndr_size_string_array(t->strings, t->num_of_strings, LIBNDR_FLAG_STR_NULLTERM);
885         t->data                         = data_blob_talloc(mem_ctx, e->Data, e->DataLength);
886         /* t->padding                   = r->Pad; */
887
888         return NT_STATUS_OK;
889 }
890
891 /********************************************************************
892  ********************************************************************/
893
894 NTSTATUS evlog_tdb_entry_to_evt_entry(TALLOC_CTX *mem_ctx,
895                                       const struct eventlog_Record_tdb *t,
896                                       struct EVENTLOGRECORD *e)
897 {
898         uint32_t i;
899
900         ZERO_STRUCTP(e);
901
902         e->Length               = t->size;
903         e->Reserved             = t->reserved;
904         e->RecordNumber         = t->record_number;
905         e->TimeGenerated        = t->time_generated;
906         e->TimeWritten          = t->time_written;
907         e->EventID              = t->event_id;
908         e->EventType            = t->event_type;
909         e->NumStrings           = t->num_of_strings;
910         e->EventCategory        = t->event_category;
911         e->ReservedFlags        = t->reserved_flags;
912         e->ClosingRecordNumber  = t->closing_record_number;
913
914         e->StringOffset         = t->stringoffset;
915         e->UserSidLength        = t->sid_length;
916         e->UserSidOffset        = t->sid_offset;
917         e->DataLength           = t->data_length;
918         e->DataOffset           = t->data_offset;
919
920         e->SourceName           = talloc_strdup(mem_ctx, t->source_name);
921         NT_STATUS_HAVE_NO_MEMORY(e->SourceName);
922
923         e->Computername         = talloc_strdup(mem_ctx, t->computer_name);
924         NT_STATUS_HAVE_NO_MEMORY(e->Computername);
925
926         if (t->sid_length > 0) {
927                 const char *sid_str = NULL;
928                 size_t len;
929                 if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
930                                            t->sid.data, t->sid.length,
931                                            &sid_str, &len, false)) {
932                         return NT_STATUS_INVALID_SID;
933                 }
934                 if (len > 0) {
935                         e->UserSid = *string_sid_talloc(mem_ctx, sid_str);
936                 }
937         }
938
939         e->Strings              = talloc_array(mem_ctx, const char *, t->num_of_strings);
940         for (i=0; i < t->num_of_strings; i++) {
941                 e->Strings[i] = talloc_strdup(e->Strings, t->strings[i]);
942                 NT_STATUS_HAVE_NO_MEMORY(e->Strings[i]);
943         }
944
945         e->Data                 = (uint8_t *)talloc_memdup(mem_ctx, t->data.data, t->data_length);
946         e->Pad                  = talloc_strdup(mem_ctx, "");
947         NT_STATUS_HAVE_NO_MEMORY(e->Pad);
948
949         e->Length2              = t->size;
950
951         return NT_STATUS_OK;
952 }