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