1/*
2 * Copyright (c) 1993, 1994, 1995, 1996, 1998
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25
26#include <stdio.h>
27#include <stdarg.h>
28#include <stdlib.h>
29
30#ifdef _WIN32
31#include <windows.h>
32#else
33#include <syslog.h>
34#endif
35
36#include "portability.h"
37
38#include "log.h"
39
40static int log_to_systemlog;
41static int log_debug_messages;
42
43static void rpcapd_vlog_stderr(log_priority,
44    PCAP_FORMAT_STRING(const char *), va_list) PCAP_PRINTFLIKE(2, 0);
45
46static void rpcapd_vlog_stderr(log_priority priority, const char *message, va_list ap)
47{
48	const char *tag;
49
50	/*
51	 * Squelch warnings from compilers that *don't* assume that
52	 * priority always has a valid enum value and therefore don't
53	 * assume that we'll always go through one of the case arms.
54	 *
55	 * If we have a default case, compilers that *do* assume that
56	 * will then complain about the default case code being
57	 * unreachable.
58	 *
59	 * Damned if you do, damned if you don't.
60	 */
61	tag = "";
62
63	switch (priority) {
64
65	case LOGPRIO_DEBUG:
66		tag = "DEBUG: ";
67		break;
68
69	case LOGPRIO_INFO:
70		tag = "";
71		break;
72
73	case LOGPRIO_WARNING:
74		tag = "warning: ";
75		break;
76
77	case LOGPRIO_ERROR:
78		tag = "error: ";
79		break;
80	}
81
82	fprintf(stderr, "rpcapd: %s", tag);
83	vfprintf(stderr, message, ap);
84	putc('\n', stderr);
85}
86
87static void rpcapd_vlog_systemlog(log_priority,
88    PCAP_FORMAT_STRING(const char *), va_list) PCAP_PRINTFLIKE(2, 0);
89
90#ifdef _WIN32
91#define MESSAGE_SUBKEY \
92    "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\rpcapd"
93
94static void rpcapd_vlog_systemlog(log_priority priority, const char *message,
95    va_list ap)
96{
97#if 0
98	static int initialized = 0;
99	HKEY hey_handle;
100	static HANDLE log_handle;
101	WORD eventlog_type;
102	DWORD event_id;
103	char msgbuf[1024];
104	char *strings[1];
105
106	if (!initialized) {
107		/*
108		 * Register our message stuff in the Registry.
109		 *
110		 * First, create the registry key for us.  If the key
111		 * already exists, this succeeds and returns a handle
112		 * for it.
113		 */
114		if (RegCreateKey(HKEY_LOCAL_MACHINE, MESSAGE_SUBKEY,
115		    &key_handle) != ERROR_SUCCESS) {
116			/*
117			 * Failed - give up and just log this message,
118			 * and all subsequent messages, to the
119			 * standard error.
120			 */
121			log_to_systemlog = 0;
122			initialized = 1;
123			rpcapd_vlog_stderr(priority, message, ap);
124			return;
125		}
126		log_handle = RegisterEventSource(NULL, "rpcapd");
127		initialized = 1;
128	}
129
130	switch (priority) {
131
132	case LOGPRIO_DEBUG:
133		//
134		// XXX - what *should* we do about debug messages?
135		//
136		eventlog_type = EVENTLOG_INFORMATION_TYPE;
137		event_id = RPCAPD_INFO_ID;
138		break;
139
140	case LOGPRIO_INFO:
141		eventlog_type = EVENTLOG_INFORMATION_TYPE;
142		event_id = RPCAPD_INFO_ID;
143		break;
144
145	case LOGPRIO_WARNING:
146		eventlog_type = EVENTLOG_WARNING_TYPE;
147		event_id = RPCAPD_WARNING_ID;
148		break;
149
150	case LOGPRIO_ERROR:
151		eventlog_type = EVENTLOG_ERROR_TYPE;
152		event_id = RPCAPD_ERROR_ID;
153		break;
154
155	default:
156		/* Don't do this. */
157		return;
158	}
159
160	vsprintf(msgbuf, message, ap);
161
162	strings[0] = msgbuf;
163	/*
164	 * If this fails, how are we going to report it?
165	 */
166	(void) ReportEvent(log_handle, eventlog_type, 0, event_id, NULL, 1, 0,
167	    strings, NULL);
168#else
169	rpcapd_vlog_stderr(priority, message, ap);
170#endif
171}
172#else
173static void rpcapd_vlog_systemlog(log_priority priority, const char *message,
174    va_list ap)
175{
176	static int initialized = 0;
177	int syslog_priority;
178
179	if (!initialized) {
180		//
181		// Open the log.
182		//
183		openlog("rpcapd", LOG_PID, LOG_DAEMON);
184		initialized = 1;
185	}
186
187	switch (priority) {
188
189	case LOGPRIO_DEBUG:
190		syslog_priority = LOG_DEBUG;
191		break;
192
193	case LOGPRIO_INFO:
194		syslog_priority = LOG_INFO;
195		break;
196
197	case LOGPRIO_WARNING:
198		syslog_priority = LOG_WARNING;
199		break;
200
201	case LOGPRIO_ERROR:
202		syslog_priority = LOG_ERR;
203		break;
204
205	default:
206		/* Don't do this. */
207		return;
208	}
209
210#ifdef HAVE_VSYSLOG
211	vsyslog(syslog_priority, message, ap);
212#else
213	/*
214	 * Thanks, IBM, for not providing vsyslog() in AIX!
215	 *
216	 * They also warn that the syslog functions shouldn't
217	 * be used in multithreaded programs, but the only thing
218	 * obvious that seems to make the syslog_r functions
219	 * better is that they have an additional argument
220	 * that points to the information that's static to
221	 * the syslog code in non-thread-safe versions.  Most
222	 * of that data is set by openlog(); since we already
223	 * do an openlog before doing logging, and don't
224	 * change that data afterwards, I suspect that, in
225	 * practice, the regular syslog routines are OK for
226	 * us (especially given that we'd end up having one
227	 * static struct syslog_data anyway, which means we'd
228	 * just be like the non-thread-safe version).
229	 */
230	char logbuf[1024+1];
231
232	vsnprintf(logbuf, sizeof logbuf, message, ap);
233	syslog(syslog_priority, "%s", logbuf);
234#endif
235}
236#endif
237
238void rpcapd_log_set(int log_to_systemlog_arg, int log_debug_messages_arg)
239{
240	log_debug_messages = log_debug_messages_arg;
241	log_to_systemlog = log_to_systemlog_arg;
242}
243
244void rpcapd_log(log_priority priority, const char *message, ...)
245{
246	va_list ap;
247
248	if (priority != LOGPRIO_DEBUG || log_debug_messages) {
249		va_start(ap, message);
250		if (log_to_systemlog)
251		{
252			rpcapd_vlog_systemlog(priority, message, ap);
253		}
254		else
255		{
256			rpcapd_vlog_stderr(priority, message, ap);
257		}
258		va_end(ap);
259	}
260}
261