• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.0.25b/source/rpc_server/
1/*
2 *  Unix SMB/CIFS implementation.
3 *  RPC Pipe client / server routines
4 *  Copyright (C) Marcin Krzysztof Porwit    2005,
5 *  Copyright (C) Brian Moran                2005,
6 *  Copyright (C) Gerald (Jerry) Carter      2005.
7 *
8 *  This program is free software; you can redistribute it and/or modify
9 *  it under the terms of the GNU General Public License as published by
10 *  the Free Software Foundation; either version 2 of the License, or
11 *  (at your option) any later version.
12 *
13 *  This program is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *  GNU General Public License for more details.
17 *
18 *  You should have received a copy of the GNU General Public License
19 *  along with this program; if not, write to the Free Software
20 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23#include "includes.h"
24
25#undef  DBGC_CLASS
26#define DBGC_CLASS DBGC_RPC_SRV
27
28typedef struct {
29	char *logname;
30	ELOG_TDB *etdb;
31	uint32 current_record;
32	uint32 num_records;
33	uint32 oldest_entry;
34	uint32 flags;
35	uint32 access_granted;
36} EVENTLOG_INFO;
37
38/********************************************************************
39 ********************************************************************/
40
41static void free_eventlog_info( void *ptr )
42{
43	EVENTLOG_INFO *elog = (EVENTLOG_INFO *)ptr;
44
45	if ( elog->etdb )
46		elog_close_tdb( elog->etdb, False );
47
48	TALLOC_FREE( elog );
49}
50
51/********************************************************************
52 ********************************************************************/
53
54static EVENTLOG_INFO *find_eventlog_info_by_hnd( pipes_struct * p,
55						POLICY_HND * handle )
56{
57	EVENTLOG_INFO *info;
58
59	if ( !find_policy_by_hnd( p, handle, (void **)(void *)&info ) ) {
60		DEBUG( 2,
61		       ( "find_eventlog_info_by_hnd: eventlog not found.\n" ) );
62		return NULL;
63	}
64
65	return info;
66}
67
68/********************************************************************
69********************************************************************/
70
71static BOOL elog_check_access( EVENTLOG_INFO *info, NT_USER_TOKEN *token )
72{
73	char *tdbname = elog_tdbname( info->logname );
74	SEC_DESC *sec_desc;
75	BOOL ret;
76	NTSTATUS ntstatus;
77
78	if ( !tdbname )
79		return False;
80
81	/* get the security descriptor for the file */
82
83	sec_desc = get_nt_acl_no_snum( info, tdbname );
84	SAFE_FREE( tdbname );
85
86	if ( !sec_desc ) {
87		DEBUG(5,("elog_check_access: Unable to get NT ACL for %s\n",
88			tdbname));
89		return False;
90	}
91
92	/* root free pass */
93
94	if ( geteuid() == sec_initial_uid() ) {
95		DEBUG(5,("elog_check_access: using root's token\n"));
96		token = get_root_nt_token();
97	}
98
99	/* run the check, try for the max allowed */
100
101	ret = se_access_check( sec_desc, token, MAXIMUM_ALLOWED_ACCESS,
102		&info->access_granted, &ntstatus );
103
104	if ( sec_desc )
105		TALLOC_FREE( sec_desc );
106
107	if ( !ret ) {
108		DEBUG(8,("elog_check_access: se_access_check() return %s\n",
109			nt_errstr( ntstatus)));
110		return False;
111	}
112
113	/* we have to have READ permission for a successful open */
114
115	return ( info->access_granted & SA_RIGHT_FILE_READ_DATA );
116}
117
118/********************************************************************
119 ********************************************************************/
120
121static BOOL elog_validate_logname( const char *name )
122{
123	int i;
124	const char **elogs = lp_eventlog_list();
125
126	if (!elogs) {
127		return False;
128	}
129
130	for ( i=0; elogs[i]; i++ ) {
131		if ( strequal( name, elogs[i] ) )
132			return True;
133	}
134
135	return False;
136}
137
138/********************************************************************
139********************************************************************/
140
141static BOOL get_num_records_hook( EVENTLOG_INFO * info )
142{
143	int next_record;
144	int oldest_record;
145
146	if ( !info->etdb ) {
147		DEBUG( 10, ( "No open tdb for %s\n", info->logname ) );
148		return False;
149	}
150
151	/* lock the tdb since we have to get 2 records */
152
153	tdb_lock_bystring_with_timeout( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD, 1 );
154	next_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
155	oldest_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_OLDEST_ENTRY);
156	tdb_unlock_bystring( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
157
158	DEBUG( 8,
159	       ( "Oldest Record %d; Next Record %d\n", oldest_record,
160		 next_record ) );
161
162	info->num_records = ( next_record - oldest_record );
163	info->oldest_entry = oldest_record;
164
165	return True;
166}
167
168/********************************************************************
169 ********************************************************************/
170
171static BOOL get_oldest_entry_hook( EVENTLOG_INFO * info )
172{
173	/* it's the same thing */
174	return get_num_records_hook( info );
175}
176
177/********************************************************************
178 ********************************************************************/
179
180static NTSTATUS elog_open( pipes_struct * p, const char *logname, POLICY_HND *hnd )
181{
182	EVENTLOG_INFO *elog;
183
184	/* first thing is to validate the eventlog name */
185
186	if ( !elog_validate_logname( logname ) )
187		return NT_STATUS_OBJECT_PATH_INVALID;
188
189	if ( !(elog = TALLOC_ZERO_P( NULL, EVENTLOG_INFO )) )
190		return NT_STATUS_NO_MEMORY;
191
192	elog->logname = talloc_strdup( elog, logname );
193
194	/* Open the tdb first (so that we can create any new tdbs if necessary).
195	   We have to do this as root and then use an internal access check
196	   on the file permissions since you can only have a tdb open once
197	   in a single process */
198
199	become_root();
200	elog->etdb = elog_open_tdb( elog->logname, False );
201	unbecome_root();
202
203	if ( !elog->etdb ) {
204		/* according to MSDN, if the logfile cannot be found, we should
205		  default to the "Application" log */
206
207		if ( !strequal( logname, ELOG_APPL ) ) {
208
209			TALLOC_FREE( elog->logname );
210
211			elog->logname = talloc_strdup( elog, ELOG_APPL );
212
213			/* do the access check */
214			if ( !elog_check_access( elog, p->pipe_user.nt_user_token ) ) {
215				TALLOC_FREE( elog );
216				return NT_STATUS_ACCESS_DENIED;
217			}
218
219			become_root();
220			elog->etdb = elog_open_tdb( elog->logname, False );
221			unbecome_root();
222		}
223
224		if ( !elog->etdb ) {
225			TALLOC_FREE( elog );
226			return NT_STATUS_ACCESS_DENIED;	/* ??? */
227		}
228	}
229
230	/* now do the access check.  Close the tdb if we fail here */
231
232	if ( !elog_check_access( elog, p->pipe_user.nt_user_token ) ) {
233		elog_close_tdb( elog->etdb, False );
234		TALLOC_FREE( elog );
235		return NT_STATUS_ACCESS_DENIED;
236	}
237
238	/* create the policy handle */
239
240	if ( !create_policy_hnd
241	     ( p, hnd, free_eventlog_info, ( void * ) elog ) ) {
242		free_eventlog_info( elog );
243		return NT_STATUS_NO_MEMORY;
244	}
245
246	/* set the initial current_record pointer */
247
248	if ( !get_oldest_entry_hook( elog ) ) {
249		DEBUG(3,("elog_open: Successfully opened eventlog but can't "
250			"get any information on internal records!\n"));
251	}
252
253	elog->current_record = elog->oldest_entry;
254
255	return NT_STATUS_OK;
256}
257
258/********************************************************************
259 ********************************************************************/
260
261static NTSTATUS elog_close( pipes_struct *p, POLICY_HND *hnd )
262{
263        if ( !( close_policy_hnd( p, hnd ) ) ) {
264                return NT_STATUS_INVALID_HANDLE;
265        }
266
267	return NT_STATUS_OK;
268}
269
270/*******************************************************************
271 *******************************************************************/
272
273static int elog_size( EVENTLOG_INFO *info )
274{
275	if ( !info || !info->etdb ) {
276		DEBUG(0,("elog_size: Invalid info* structure!\n"));
277		return 0;
278	}
279
280	return elog_tdb_size( ELOG_TDB_CTX(info->etdb), NULL, NULL );
281}
282
283/********************************************************************
284  For the given tdb, get the next eventlog record into the passed
285  Eventlog_entry.  returns NULL if it can't get the record for some reason.
286 ********************************************************************/
287
288static Eventlog_entry *get_eventlog_record( prs_struct * ps, TDB_CONTEXT * tdb,
289				     int recno, Eventlog_entry * ee )
290{
291	TDB_DATA ret, key;
292
293	int srecno;
294	int reclen;
295	int len;
296
297	pstring *wpsource, *wpcomputer, *wpsid, *wpstrs, *puserdata;
298
299	key.dsize = sizeof( int32 );
300
301	srecno = recno;
302	key.dptr = ( char * ) &srecno;
303
304	ret = tdb_fetch( tdb, key );
305
306	if ( ret.dsize == 0 ) {
307		DEBUG( 8,
308		       ( "Can't find a record for the key, record %d\n",
309			 recno ) );
310		return NULL;
311	}
312
313	len = tdb_unpack( ret.dptr, ret.dsize, "d", &reclen );
314
315	DEBUG( 10, ( "Unpacking record %d, size is %d\n", srecno, len ) );
316
317	if ( !len )
318		return NULL;
319
320	/* ee = PRS_ALLOC_MEM(ps, Eventlog_entry, 1); */
321
322	if ( !ee )
323		return NULL;
324
325	len = tdb_unpack( ret.dptr, ret.dsize, "ddddddwwwwddddddBBdBBBd",
326			  &ee->record.length, &ee->record.reserved1,
327			  &ee->record.record_number,
328			  &ee->record.time_generated,
329			  &ee->record.time_written, &ee->record.event_id,
330			  &ee->record.event_type, &ee->record.num_strings,
331			  &ee->record.event_category, &ee->record.reserved2,
332			  &ee->record.closing_record_number,
333			  &ee->record.string_offset,
334			  &ee->record.user_sid_length,
335			  &ee->record.user_sid_offset,
336			  &ee->record.data_length, &ee->record.data_offset,
337			  &ee->data_record.source_name_len, &wpsource,
338			  &ee->data_record.computer_name_len, &wpcomputer,
339			  &ee->data_record.sid_padding,
340			  &ee->record.user_sid_length, &wpsid,
341			  &ee->data_record.strings_len, &wpstrs,
342			  &ee->data_record.user_data_len, &puserdata,
343			  &ee->data_record.data_padding );
344	DEBUG( 10,
345	       ( "Read record %d, len in tdb was %d\n",
346		 ee->record.record_number, len ) );
347
348	/* have to do the following because the tdb_unpack allocs a buff, stuffs a pointer to the buff
349	   into it's 2nd argment for 'B' */
350
351	if ( wpcomputer )
352		memcpy( ee->data_record.computer_name, wpcomputer,
353			ee->data_record.computer_name_len );
354	if ( wpsource )
355		memcpy( ee->data_record.source_name, wpsource,
356			ee->data_record.source_name_len );
357
358	if ( wpsid )
359		memcpy( ee->data_record.sid, wpsid,
360			ee->record.user_sid_length );
361	if ( wpstrs )
362		memcpy( ee->data_record.strings, wpstrs,
363			ee->data_record.strings_len );
364
365	/* note that userdata is a pstring */
366	if ( puserdata )
367		memcpy( ee->data_record.user_data, puserdata,
368			ee->data_record.user_data_len );
369
370	SAFE_FREE( wpcomputer );
371	SAFE_FREE( wpsource );
372	SAFE_FREE( wpsid );
373	SAFE_FREE( wpstrs );
374	SAFE_FREE( puserdata );
375
376	DEBUG( 10, ( "get_eventlog_record: read back %d\n", len ) );
377	DEBUG( 10,
378	       ( "get_eventlog_record: computer_name %d is ",
379		 ee->data_record.computer_name_len ) );
380	SAFE_FREE( ret.dptr );
381	return ee;
382}
383
384/********************************************************************
385 note that this can only be called AFTER the table is constructed,
386 since it uses the table to find the tdb handle
387 ********************************************************************/
388
389static BOOL sync_eventlog_params( EVENTLOG_INFO *info )
390{
391	pstring path;
392	uint32 uiMaxSize;
393	uint32 uiRetention;
394	REGISTRY_KEY *keyinfo;
395	REGISTRY_VALUE *val;
396	REGVAL_CTR *values;
397	WERROR wresult;
398	char *elogname = info->logname;
399
400	DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) );
401
402	if ( !info->etdb ) {
403		DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) );
404		return False;
405	}
406	/* set resonable defaults.  512Kb on size and 1 week on time */
407
408	uiMaxSize = 0x80000;
409	uiRetention = 604800;
410
411	/* the general idea is to internally open the registry
412	   key and retreive the values.  That way we can continue
413	   to use the same fetch/store api that we use in
414	   srv_reg_nt.c */
415
416	pstr_sprintf( path, "%s/%s", KEY_EVENTLOG, elogname );
417
418	wresult =
419		regkey_open_internal( &keyinfo, path, get_root_nt_token(  ),
420				      REG_KEY_READ );
421
422	if ( !W_ERROR_IS_OK( wresult ) ) {
423		DEBUG( 4,
424		       ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
425			 path, dos_errstr( wresult ) ) );
426		return False;
427	}
428
429	if ( !( values = TALLOC_ZERO_P( keyinfo, REGVAL_CTR ) ) ) {
430		TALLOC_FREE( keyinfo );
431		DEBUG( 0, ( "control_eventlog_hook: talloc() failed!\n" ) );
432
433		return False;
434	}
435	fetch_reg_values( keyinfo, values );
436
437	if ( ( val = regval_ctr_getvalue( values, "Retention" ) ) != NULL )
438		uiRetention = IVAL( regval_data_p( val ), 0 );
439
440	if ( ( val = regval_ctr_getvalue( values, "MaxSize" ) ) != NULL )
441		uiMaxSize = IVAL( regval_data_p( val ), 0 );
442
443	regkey_close_internal( keyinfo );
444
445	tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
446	tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
447
448	return True;
449}
450
451/********************************************************************
452 ********************************************************************/
453
454static Eventlog_entry *read_package_entry( prs_struct * ps,
455					   EVENTLOG_Q_READ_EVENTLOG * q_u,
456					   EVENTLOG_R_READ_EVENTLOG * r_u,
457					   Eventlog_entry * entry )
458{
459	uint8 *offset;
460	Eventlog_entry *ee_new = NULL;
461
462	ee_new = PRS_ALLOC_MEM( ps, Eventlog_entry, 1 );
463	if ( ee_new == NULL ) {
464		return NULL;
465	}
466
467	entry->data_record.sid_padding =
468		( ( 4 -
469		    ( ( entry->data_record.source_name_len +
470			entry->data_record.computer_name_len ) % 4 ) ) % 4 );
471	entry->data_record.data_padding =
472		( 4 -
473		  ( ( entry->data_record.strings_len +
474		      entry->data_record.user_data_len ) % 4 ) ) % 4;
475	entry->record.length = sizeof( Eventlog_record );
476	entry->record.length += entry->data_record.source_name_len;
477	entry->record.length += entry->data_record.computer_name_len;
478	if ( entry->record.user_sid_length == 0 ) {
479		/* Should not pad to a DWORD boundary for writing out the sid if there is
480		   no SID, so just propagate the padding to pad the data */
481		entry->data_record.data_padding +=
482			entry->data_record.sid_padding;
483		entry->data_record.sid_padding = 0;
484	}
485	DEBUG( 10,
486	       ( "sid_padding is [%d].\n", entry->data_record.sid_padding ) );
487	DEBUG( 10,
488	       ( "data_padding is [%d].\n",
489		 entry->data_record.data_padding ) );
490
491	entry->record.length += entry->data_record.sid_padding;
492	entry->record.length += entry->record.user_sid_length;
493	entry->record.length += entry->data_record.strings_len;
494	entry->record.length += entry->data_record.user_data_len;
495	entry->record.length += entry->data_record.data_padding;
496	/* need another copy of length at the end of the data */
497	entry->record.length += sizeof( entry->record.length );
498	DEBUG( 10,
499	       ( "entry->record.length is [%d].\n", entry->record.length ) );
500	entry->data =
501		PRS_ALLOC_MEM( ps, uint8,
502			       entry->record.length -
503			       sizeof( Eventlog_record ) -
504			       sizeof( entry->record.length ) );
505	if ( entry->data == NULL ) {
506		return NULL;
507	}
508	offset = entry->data;
509	memcpy( offset, &( entry->data_record.source_name ),
510		entry->data_record.source_name_len );
511	offset += entry->data_record.source_name_len;
512	memcpy( offset, &( entry->data_record.computer_name ),
513		entry->data_record.computer_name_len );
514	offset += entry->data_record.computer_name_len;
515	/* SID needs to be DWORD-aligned */
516	offset += entry->data_record.sid_padding;
517	entry->record.user_sid_offset =
518		sizeof( Eventlog_record ) + ( offset - entry->data );
519	memcpy( offset, &( entry->data_record.sid ),
520		entry->record.user_sid_length );
521	offset += entry->record.user_sid_length;
522	/* Now do the strings */
523	entry->record.string_offset =
524		sizeof( Eventlog_record ) + ( offset - entry->data );
525	memcpy( offset, &( entry->data_record.strings ),
526		entry->data_record.strings_len );
527	offset += entry->data_record.strings_len;
528	/* Now do the data */
529	entry->record.data_length = entry->data_record.user_data_len;
530	entry->record.data_offset =
531		sizeof( Eventlog_record ) + ( offset - entry->data );
532	memcpy( offset, &( entry->data_record.user_data ),
533		entry->data_record.user_data_len );
534	offset += entry->data_record.user_data_len;
535
536	memcpy( &( ee_new->record ), &entry->record,
537		sizeof( Eventlog_record ) );
538	memcpy( &( ee_new->data_record ), &entry->data_record,
539		sizeof( Eventlog_data_record ) );
540	ee_new->data = entry->data;
541
542	return ee_new;
543}
544
545/********************************************************************
546 ********************************************************************/
547
548static BOOL add_record_to_resp( EVENTLOG_R_READ_EVENTLOG * r_u,
549				Eventlog_entry * ee_new )
550{
551	Eventlog_entry *insert_point;
552
553	insert_point = r_u->entry;
554
555	if ( NULL == insert_point ) {
556		r_u->entry = ee_new;
557		ee_new->next = NULL;
558	} else {
559		while ( ( NULL != insert_point->next ) ) {
560			insert_point = insert_point->next;
561		}
562		ee_new->next = NULL;
563		insert_point->next = ee_new;
564	}
565	r_u->num_records++;
566	r_u->num_bytes_in_resp += ee_new->record.length;
567
568	return True;
569}
570
571/********************************************************************
572 ********************************************************************/
573
574NTSTATUS _eventlog_open_eventlog( pipes_struct * p,
575				EVENTLOG_Q_OPEN_EVENTLOG * q_u,
576				EVENTLOG_R_OPEN_EVENTLOG * r_u )
577{
578	fstring servername, logname;
579	EVENTLOG_INFO *info;
580	NTSTATUS result;
581
582	fstrcpy( servername, "" );
583	if ( q_u->servername.string ) {
584		rpcstr_pull( servername, q_u->servername.string->buffer,
585			     sizeof( servername ),
586			     q_u->servername.string->uni_str_len * 2, 0 );
587	}
588
589	fstrcpy( logname, "" );
590	if ( q_u->logname.string ) {
591		rpcstr_pull( logname, q_u->logname.string->buffer,
592			     sizeof( logname ),
593			     q_u->logname.string->uni_str_len * 2, 0 );
594	}
595
596	DEBUG( 10,("_eventlog_open_eventlog: Server [%s], Log [%s]\n",
597		servername, logname ));
598
599	/* according to MSDN, if the logfile cannot be found, we should
600	  default to the "Application" log */
601
602	if ( !NT_STATUS_IS_OK( result = elog_open( p, logname, &r_u->handle )) )
603		return result;
604
605	if ( !(info = find_eventlog_info_by_hnd( p, &r_u->handle )) ) {
606		DEBUG(0,("_eventlog_open_eventlog: eventlog (%s) opened but unable to find handle!\n",
607			logname ));
608		elog_close( p, &r_u->handle );
609		return NT_STATUS_INVALID_HANDLE;
610	}
611
612	DEBUG(10,("_eventlog_open_eventlog: Size [%d]\n", elog_size( info )));
613
614	sync_eventlog_params( info );
615	prune_eventlog( ELOG_TDB_CTX(info->etdb) );
616
617	return NT_STATUS_OK;
618}
619
620/********************************************************************
621 This call still needs some work
622 ********************************************************************/
623
624NTSTATUS _eventlog_clear_eventlog( pipes_struct * p,
625				 EVENTLOG_Q_CLEAR_EVENTLOG * q_u,
626				 EVENTLOG_R_CLEAR_EVENTLOG * r_u )
627{
628	EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
629	pstring backup_file_name;
630
631	if ( !info )
632		return NT_STATUS_INVALID_HANDLE;
633
634	pstrcpy( backup_file_name, "" );
635	if ( q_u->backupfile.string ) {
636		rpcstr_pull( backup_file_name, q_u->backupfile.string->buffer,
637			     sizeof( backup_file_name ),
638			     q_u->backupfile.string->uni_str_len * 2, 0 );
639
640		DEBUG(8,( "_eventlog_clear_eventlog: Using [%s] as the backup "
641			"file name for log [%s].",
642			 backup_file_name, info->logname ) );
643	}
644
645	/* check for WRITE access to the file */
646
647	if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) )
648		return NT_STATUS_ACCESS_DENIED;
649
650	/* Force a close and reopen */
651
652	elog_close_tdb( info->etdb, True );
653	become_root();
654	info->etdb = elog_open_tdb( info->logname, True );
655	unbecome_root();
656
657	if ( !info->etdb )
658		return NT_STATUS_ACCESS_DENIED;
659
660	return NT_STATUS_OK;
661}
662
663/********************************************************************
664 ********************************************************************/
665
666NTSTATUS _eventlog_close_eventlog( pipes_struct * p,
667				 EVENTLOG_Q_CLOSE_EVENTLOG * q_u,
668				 EVENTLOG_R_CLOSE_EVENTLOG * r_u )
669{
670	return elog_close( p, &q_u->handle );
671}
672
673/********************************************************************
674 ********************************************************************/
675
676NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
677				EVENTLOG_Q_READ_EVENTLOG * q_u,
678				EVENTLOG_R_READ_EVENTLOG * r_u )
679{
680	EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
681	Eventlog_entry entry, *ee_new;
682	uint32 num_records_read = 0;
683	prs_struct *ps;
684	int bytes_left, record_number;
685	uint32 elog_read_type, elog_read_dir;
686
687	if (info == NULL) {
688		return NT_STATUS_INVALID_HANDLE;
689	}
690
691	info->flags = q_u->flags;
692	ps = &p->out_data.rdata;
693
694	bytes_left = q_u->max_read_size;
695
696	if ( !info->etdb )
697		return NT_STATUS_ACCESS_DENIED;
698
699	/* check for valid flags.  Can't use the sequential and seek flags together */
700
701	elog_read_type = q_u->flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
702	elog_read_dir = q_u->flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ);
703
704	if ( elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ)
705		||  elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ) )
706	{
707		DEBUG(3,("_eventlog_read_eventlog: Invalid flags [0x%x] for ReadEventLog\n", q_u->flags));
708		return NT_STATUS_INVALID_PARAMETER;
709	}
710
711	/* a sequential read should ignore the offset */
712
713	if ( elog_read_type & EVENTLOG_SEQUENTIAL_READ )
714		record_number = info->current_record;
715	else
716		record_number = q_u->offset;
717
718	while ( bytes_left > 0 ) {
719
720		/* assume that when the record fetch fails, that we are done */
721
722		if ( !get_eventlog_record ( ps, ELOG_TDB_CTX(info->etdb), record_number, &entry ) )
723			break;
724
725		DEBUG( 8, ( "Retrieved record %d\n", record_number ) );
726
727		/* Now see if there is enough room to add */
728
729		if ( !(ee_new = read_package_entry( ps, q_u, r_u,&entry )) )
730			return NT_STATUS_NO_MEMORY;
731
732		if ( r_u->num_bytes_in_resp + ee_new->record.length > q_u->max_read_size ) {
733			r_u->bytes_in_next_record = ee_new->record.length;
734
735			/* response would be too big to fit in client-size buffer */
736
737			bytes_left = 0;
738			break;
739		}
740
741		add_record_to_resp( r_u, ee_new );
742		bytes_left -= ee_new->record.length;
743		ZERO_STRUCT( entry );
744		num_records_read = r_u->num_records - num_records_read;
745
746		DEBUG( 10, ( "_eventlog_read_eventlog: read [%d] records for a total "
747			"of [%d] records using [%d] bytes out of a max of [%d].\n",
748			 num_records_read, r_u->num_records,
749			 r_u->num_bytes_in_resp,
750			 q_u->max_read_size ) );
751
752		if ( info->flags & EVENTLOG_FORWARDS_READ )
753			record_number++;
754		else
755			record_number--;
756
757		/* update the eventlog record pointer */
758
759		info->current_record = record_number;
760	}
761
762	/* crazy by WinXP uses NT_STATUS_BUFFER_TOO_SMALL to
763	   say when there are no more records */
764
765	return (num_records_read ? NT_STATUS_OK : NT_STATUS_BUFFER_TOO_SMALL);
766}
767
768/********************************************************************
769 ********************************************************************/
770
771NTSTATUS _eventlog_get_oldest_entry( pipes_struct * p,
772				   EVENTLOG_Q_GET_OLDEST_ENTRY * q_u,
773				   EVENTLOG_R_GET_OLDEST_ENTRY * r_u )
774{
775	EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
776
777	if (info == NULL) {
778		return NT_STATUS_INVALID_HANDLE;
779	}
780
781	if ( !( get_oldest_entry_hook( info ) ) )
782		return NT_STATUS_ACCESS_DENIED;
783
784	r_u->oldest_entry = info->oldest_entry;
785
786	return NT_STATUS_OK;
787}
788
789/********************************************************************
790 ********************************************************************/
791
792NTSTATUS _eventlog_get_num_records( pipes_struct * p,
793				  EVENTLOG_Q_GET_NUM_RECORDS * q_u,
794				  EVENTLOG_R_GET_NUM_RECORDS * r_u )
795{
796	EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, &q_u->handle );
797
798	if (info == NULL) {
799		return NT_STATUS_INVALID_HANDLE;
800	}
801
802	if ( !( get_num_records_hook( info ) ) )
803		return NT_STATUS_ACCESS_DENIED;
804
805	r_u->num_records = info->num_records;
806
807	return NT_STATUS_OK;
808}
809