1/*
2   Unix SMB/CIFS implementation.
3   RPC pipe client
4
5   Copyright (C) Günther Deschner 2009
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include "includes.h"
22#include "rpcclient.h"
23#include "../librpc/gen_ndr/cli_eventlog.h"
24
25static NTSTATUS get_eventlog_handle(struct rpc_pipe_client *cli,
26				    TALLOC_CTX *mem_ctx,
27				    const char *log,
28				    struct policy_handle *handle)
29{
30	NTSTATUS status;
31	struct eventlog_OpenUnknown0 unknown0;
32	struct lsa_String logname, servername;
33
34	unknown0.unknown0 = 0x005c;
35	unknown0.unknown1 = 0x0001;
36
37	init_lsa_String(&logname, log);
38	init_lsa_String(&servername, NULL);
39
40	status = rpccli_eventlog_OpenEventLogW(cli, mem_ctx,
41					       &unknown0,
42					       &logname,
43					       &servername,
44					       0x00000001, /* major */
45					       0x00000001, /* minor */
46					       handle);
47	if (!NT_STATUS_IS_OK(status)) {
48		return status;
49	}
50
51	return NT_STATUS_OK;
52}
53
54static NTSTATUS cmd_eventlog_readlog(struct rpc_pipe_client *cli,
55				     TALLOC_CTX *mem_ctx,
56				     int argc,
57				     const char **argv)
58{
59	NTSTATUS status = NT_STATUS_OK;
60	struct policy_handle handle;
61
62	uint32_t flags = EVENTLOG_BACKWARDS_READ |
63			 EVENTLOG_SEQUENTIAL_READ;
64	uint32_t offset = 0;
65	uint32_t number_of_bytes = 0;
66	uint8_t *data = NULL;
67	uint32_t sent_size = 0;
68	uint32_t real_size = 0;
69
70	if (argc < 2 || argc > 4) {
71		printf("Usage: %s logname [offset] [number_of_bytes]\n", argv[0]);
72		return NT_STATUS_OK;
73	}
74
75	if (argc >= 3) {
76		offset = atoi(argv[2]);
77	}
78
79	if (argc >= 4) {
80		number_of_bytes = atoi(argv[3]);
81		data = talloc_array(mem_ctx, uint8_t, number_of_bytes);
82		if (!data) {
83			goto done;
84		}
85	}
86
87	status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle);
88	if (!NT_STATUS_IS_OK(status)) {
89		return status;
90	}
91
92	do {
93
94		enum ndr_err_code ndr_err;
95		DATA_BLOB blob;
96		struct EVENTLOGRECORD r;
97		uint32_t size = 0;
98		uint32_t pos = 0;
99
100		status = rpccli_eventlog_ReadEventLogW(cli, mem_ctx,
101						       &handle,
102						       flags,
103						       offset,
104						       number_of_bytes,
105						       data,
106						       &sent_size,
107						       &real_size);
108		if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL) &&
109		    real_size > 0 ) {
110			number_of_bytes = real_size;
111			data = talloc_array(mem_ctx, uint8_t, real_size);
112			if (!data) {
113				goto done;
114			}
115			status = rpccli_eventlog_ReadEventLogW(cli, mem_ctx,
116							       &handle,
117							       flags,
118							       offset,
119							       number_of_bytes,
120							       data,
121							       &sent_size,
122							       &real_size);
123		}
124
125		if (!NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) &&
126		    !NT_STATUS_IS_OK(status)) {
127			goto done;
128		}
129
130		number_of_bytes = 0;
131
132		size = IVAL(data, pos);
133
134		while (size > 0) {
135
136			blob = data_blob_const(data + pos, size);
137			/* dump_data(0, blob.data, blob.length); */
138			ndr_err = ndr_pull_struct_blob_all(&blob, mem_ctx, NULL, &r,
139					   (ndr_pull_flags_fn_t)ndr_pull_EVENTLOGRECORD);
140			if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
141				status = ndr_map_error2ntstatus(ndr_err);
142				goto done;
143			}
144
145			NDR_PRINT_DEBUG(EVENTLOGRECORD, &r);
146
147			pos += size;
148
149			if (pos + 4 > sent_size) {
150				break;
151			}
152
153			size = IVAL(data, pos);
154		}
155
156		offset++;
157
158	} while (NT_STATUS_IS_OK(status));
159
160 done:
161	rpccli_eventlog_CloseEventLog(cli, mem_ctx, &handle);
162
163	return status;
164}
165
166static NTSTATUS cmd_eventlog_numrecords(struct rpc_pipe_client *cli,
167					TALLOC_CTX *mem_ctx,
168					int argc,
169					const char **argv)
170{
171	NTSTATUS status;
172	struct policy_handle handle;
173	uint32_t number = 0;
174
175	if (argc != 2) {
176		printf("Usage: %s logname\n", argv[0]);
177		return NT_STATUS_OK;
178	}
179
180	status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle);
181	if (!NT_STATUS_IS_OK(status)) {
182		return status;
183	}
184
185	status = rpccli_eventlog_GetNumRecords(cli, mem_ctx,
186					       &handle,
187					       &number);
188	if (!NT_STATUS_IS_OK(status)) {
189		goto done;
190	}
191
192	printf("number of records: %d\n", number);
193
194 done:
195	rpccli_eventlog_CloseEventLog(cli, mem_ctx, &handle);
196
197	return status;
198}
199
200static NTSTATUS cmd_eventlog_oldestrecord(struct rpc_pipe_client *cli,
201					  TALLOC_CTX *mem_ctx,
202					  int argc,
203					  const char **argv)
204{
205	NTSTATUS status;
206	struct policy_handle handle;
207	uint32_t oldest_entry = 0;
208
209	if (argc != 2) {
210		printf("Usage: %s logname\n", argv[0]);
211		return NT_STATUS_OK;
212	}
213
214	status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle);
215	if (!NT_STATUS_IS_OK(status)) {
216		return status;
217	}
218
219	status = rpccli_eventlog_GetOldestRecord(cli, mem_ctx,
220						 &handle,
221						 &oldest_entry);
222	if (!NT_STATUS_IS_OK(status)) {
223		goto done;
224	}
225
226	printf("oldest entry: %d\n", oldest_entry);
227
228 done:
229	rpccli_eventlog_CloseEventLog(cli, mem_ctx, &handle);
230
231	return status;
232}
233
234static NTSTATUS cmd_eventlog_reportevent(struct rpc_pipe_client *cli,
235					 TALLOC_CTX *mem_ctx,
236					 int argc,
237					 const char **argv)
238{
239	NTSTATUS status;
240	struct policy_handle handle;
241
242	uint16_t num_of_strings = 1;
243	uint32_t data_size = 0;
244	struct lsa_String servername;
245	struct lsa_String *strings;
246	uint8_t *data = NULL;
247	uint32_t record_number = 0;
248	time_t time_written = 0;
249
250	if (argc != 2) {
251		printf("Usage: %s logname\n", argv[0]);
252		return NT_STATUS_OK;
253	}
254
255	status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle);
256	if (!NT_STATUS_IS_OK(status)) {
257		return status;
258	}
259
260	strings = talloc_array(mem_ctx, struct lsa_String, num_of_strings);
261	if (!strings) {
262		return NT_STATUS_NO_MEMORY;
263	}
264
265	init_lsa_String(&strings[0], "test event written by rpcclient\n");
266	init_lsa_String(&servername, NULL);
267
268	status = rpccli_eventlog_ReportEventW(cli, mem_ctx,
269					      &handle,
270					      time(NULL),
271					      EVENTLOG_INFORMATION_TYPE,
272					      0, /* event_category */
273					      0, /* event_id */
274					      num_of_strings,
275					      data_size,
276					      &servername,
277					      NULL, /* user_sid */
278					      &strings,
279					      data,
280					      0, /* flags */
281					      &record_number,
282					      &time_written);
283
284	if (!NT_STATUS_IS_OK(status)) {
285		goto done;
286	}
287
288	printf("entry: %d written at %s\n", record_number,
289		http_timestring(talloc_tos(), time_written));
290
291 done:
292	rpccli_eventlog_CloseEventLog(cli, mem_ctx, &handle);
293
294	return status;
295}
296
297static NTSTATUS cmd_eventlog_reporteventsource(struct rpc_pipe_client *cli,
298					       TALLOC_CTX *mem_ctx,
299					       int argc,
300					       const char **argv)
301{
302	NTSTATUS status;
303	struct policy_handle handle;
304
305	uint16_t num_of_strings = 1;
306	uint32_t data_size = 0;
307	struct lsa_String servername, sourcename;
308	struct lsa_String *strings;
309	uint8_t *data = NULL;
310	uint32_t record_number = 0;
311	time_t time_written = 0;
312
313	if (argc != 2) {
314		printf("Usage: %s logname\n", argv[0]);
315		return NT_STATUS_OK;
316	}
317
318	status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle);
319	if (!NT_STATUS_IS_OK(status)) {
320		return status;
321	}
322
323	strings = talloc_array(mem_ctx, struct lsa_String, num_of_strings);
324	if (!strings) {
325		return NT_STATUS_NO_MEMORY;
326	}
327
328	init_lsa_String(&strings[0], "test event written by rpcclient\n");
329	init_lsa_String(&servername, NULL);
330	init_lsa_String(&sourcename, "rpcclient");
331
332	status = rpccli_eventlog_ReportEventAndSourceW(cli, mem_ctx,
333						       &handle,
334						       time(NULL),
335						       EVENTLOG_INFORMATION_TYPE,
336						       0, /* event_category */
337						       0, /* event_id */
338						       &sourcename,
339						       num_of_strings,
340						       data_size,
341						       &servername,
342						       NULL, /* user_sid */
343						       &strings,
344						       data,
345						       0, /* flags */
346						       &record_number,
347						       &time_written);
348	if (!NT_STATUS_IS_OK(status)) {
349		goto done;
350	}
351
352	printf("entry: %d written at %s\n", record_number,
353		http_timestring(talloc_tos(), time_written));
354
355 done:
356	rpccli_eventlog_CloseEventLog(cli, mem_ctx, &handle);
357
358	return status;
359}
360
361static NTSTATUS cmd_eventlog_registerevsource(struct rpc_pipe_client *cli,
362					      TALLOC_CTX *mem_ctx,
363					      int argc,
364					      const char **argv)
365{
366	NTSTATUS status;
367	struct policy_handle log_handle;
368	struct lsa_String module_name, reg_module_name;
369	struct eventlog_OpenUnknown0 unknown0;
370
371	unknown0.unknown0 = 0x005c;
372	unknown0.unknown1 = 0x0001;
373
374	if (argc != 2) {
375		printf("Usage: %s logname\n", argv[0]);
376		return NT_STATUS_OK;
377	}
378
379	init_lsa_String(&module_name, "rpcclient");
380	init_lsa_String(&reg_module_name, NULL);
381
382	status = rpccli_eventlog_RegisterEventSourceW(cli, mem_ctx,
383						      &unknown0,
384						      &module_name,
385						      &reg_module_name,
386						      1, /* major_version */
387						      1, /* minor_version */
388						      &log_handle);
389	if (!NT_STATUS_IS_OK(status)) {
390		goto done;
391	}
392
393 done:
394	rpccli_eventlog_DeregisterEventSource(cli, mem_ctx, &log_handle);
395
396	return status;
397}
398
399static NTSTATUS cmd_eventlog_backuplog(struct rpc_pipe_client *cli,
400				       TALLOC_CTX *mem_ctx,
401				       int argc,
402				       const char **argv)
403{
404	NTSTATUS status;
405	struct policy_handle handle;
406	struct lsa_String backup_filename;
407	const char *tmp;
408
409	if (argc != 3) {
410		printf("Usage: %s logname backupname\n", argv[0]);
411		return NT_STATUS_OK;
412	}
413
414	status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle);
415	if (!NT_STATUS_IS_OK(status)) {
416		return status;
417	}
418
419	tmp = talloc_asprintf(mem_ctx, "\\??\\%s", argv[2]);
420	if (!tmp) {
421		status = NT_STATUS_NO_MEMORY;
422		goto done;
423	}
424
425	init_lsa_String(&backup_filename, tmp);
426
427	status = rpccli_eventlog_BackupEventLogW(cli, mem_ctx,
428						 &handle,
429						 &backup_filename);
430
431 done:
432	rpccli_eventlog_CloseEventLog(cli, mem_ctx, &handle);
433
434	return status;
435}
436
437static NTSTATUS cmd_eventlog_loginfo(struct rpc_pipe_client *cli,
438				     TALLOC_CTX *mem_ctx,
439				     int argc,
440				     const char **argv)
441{
442	NTSTATUS status;
443	struct policy_handle handle;
444	uint8_t *buffer = NULL;
445	uint32_t buf_size = 0;
446	uint32_t bytes_needed = 0;
447
448	if (argc != 2) {
449		printf("Usage: %s logname\n", argv[0]);
450		return NT_STATUS_OK;
451	}
452
453	status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle);
454	if (!NT_STATUS_IS_OK(status)) {
455		return status;
456	}
457
458	status = rpccli_eventlog_GetLogInformation(cli, mem_ctx,
459						   &handle,
460						   0, /* level */
461						   buffer,
462						   buf_size,
463						   &bytes_needed);
464	if (!NT_STATUS_IS_OK(status) &&
465	    !NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
466		goto done;
467	}
468
469	buf_size = bytes_needed;
470	buffer = talloc_array(mem_ctx, uint8_t, bytes_needed);
471	if (!buffer) {
472		status = NT_STATUS_NO_MEMORY;
473		goto done;
474	}
475
476	status = rpccli_eventlog_GetLogInformation(cli, mem_ctx,
477						   &handle,
478						   0, /* level */
479						   buffer,
480						   buf_size,
481						   &bytes_needed);
482	if (!NT_STATUS_IS_OK(status)) {
483		goto done;
484	}
485
486 done:
487	rpccli_eventlog_CloseEventLog(cli, mem_ctx, &handle);
488
489	return status;
490}
491
492
493struct cmd_set eventlog_commands[] = {
494	{ "EVENTLOG" },
495	{ "eventlog_readlog",		RPC_RTYPE_NTSTATUS,	cmd_eventlog_readlog,		NULL,	&ndr_table_eventlog.syntax_id,	NULL,	"Read Eventlog", "" },
496	{ "eventlog_numrecord",		RPC_RTYPE_NTSTATUS,	cmd_eventlog_numrecords,	NULL,	&ndr_table_eventlog.syntax_id,	NULL,	"Get number of records", "" },
497	{ "eventlog_oldestrecord",	RPC_RTYPE_NTSTATUS,	cmd_eventlog_oldestrecord,	NULL,	&ndr_table_eventlog.syntax_id,	NULL,	"Get oldest record", "" },
498	{ "eventlog_reportevent",	RPC_RTYPE_NTSTATUS,	cmd_eventlog_reportevent,	NULL,	&ndr_table_eventlog.syntax_id,	NULL,	"Report event", "" },
499	{ "eventlog_reporteventsource",	RPC_RTYPE_NTSTATUS,	cmd_eventlog_reporteventsource,	NULL,	&ndr_table_eventlog.syntax_id,	NULL,	"Report event and source", "" },
500	{ "eventlog_registerevsource",	RPC_RTYPE_NTSTATUS,	cmd_eventlog_registerevsource,	NULL,	&ndr_table_eventlog.syntax_id,	NULL,	"Register event source", "" },
501	{ "eventlog_backuplog",		RPC_RTYPE_NTSTATUS,	cmd_eventlog_backuplog,		NULL,	&ndr_table_eventlog.syntax_id,	NULL,	"Backup Eventlog File", "" },
502	{ "eventlog_loginfo",		RPC_RTYPE_NTSTATUS,	cmd_eventlog_loginfo,		NULL,	&ndr_table_eventlog.syntax_id,	NULL,	"Get Eventlog Information", "" },
503	{ NULL }
504};
505