addon-network-discovery.c revision 5307:ea4512a0e608
1/*
2 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 *
5 * Licensed under the Academic Free License version 2.1
6 */
7
8#pragma ident	"%Z%%M%	%I%	%E% SMI"
9
10#ifdef HAVE_CONFIG_H
11#include <config.h>
12#endif
13
14#include <stdio.h>
15#include <unistd.h>
16#include <string.h>
17#include <stdlib.h>
18#include <fcntl.h>
19#include <sys/dkio.h>
20#include <sys/stat.h>
21#include <priv.h>
22#include <glib.h>
23
24#include <dbus/dbus-glib-lowlevel.h>
25#include <libhal.h>
26
27#include "../../hald/logger.h"
28
29#include "network-discovery.h"
30#include "printer.h"
31
32#define	DBUS_INTERFACE	"org.freedesktop.Hal.Device.NetworkDiscovery"
33#define	NP(x)	(x?x:"NULL")
34#define	STRDUP(x)	(x?strdup(x):NULL)
35
36typedef struct {
37	LibHalContext *ctx;
38	gboolean enabled;
39	char *parent;
40	char *community;
41	char *network;
42} nds_snmp_cbdata_t;
43
44static nds_snmp_cbdata_t *snmp_cb_data = NULL;
45
46static int
47nds_snmp_scan(LibHalContext *ctx, char *parent, char *community, char *network)
48{
49	time_t start;
50
51	HAL_DEBUG(("nds_snmp_scan(0x%8.8x, %s, %s, %s)",
52			ctx, NP(parent), NP(community), NP(network)));
53	HAL_DEBUG(("NetworkDiscovery snmp scan initated"));
54
55	/* scan for devices */
56	time(&start);
57	if (network == NULL) {
58		GList *elem, *list = broadcast_addresses();
59
60		for (elem = list; elem != NULL; elem = g_list_next(elem)) {
61			scan_for_devices_using_snmp(ctx, parent, community,
62						(char *)elem->data);
63			free(elem->data);
64		}
65		g_list_free(list);
66	} else
67		scan_for_devices_using_snmp(ctx, parent, community, network);
68
69	/* remove devices that haven't been seen since before this scan */
70	scan_for_stale_devices(ctx, start);
71
72	HAL_DEBUG(("NetworkDiscovery snmp scan completed"));
73
74	return (0);
75}
76
77static gboolean
78nds_snmp_scan_cb(gpointer data)
79{
80	nds_snmp_cbdata_t *args = data;
81
82	if (args->enabled == FALSE) {
83		if (args->parent) free(args->parent);
84		if (args->community) free(args->community);
85		if (args->network) free(args->network);
86		free(args);
87		return (FALSE);
88	}
89
90	nds_snmp_scan(args->ctx, args->parent, args->community, args->network);
91
92	return (TRUE);
93}
94
95static int
96nds_EnablePrinterScanningViaSNMP(LibHalContext *ctx, char *parent, int interval,
97		char *community, char *network)
98{
99	HAL_DEBUG(("NetworkDiscovery.EnablePrinterScanningViaSNMP(0x%8.8x, %s, %d, %s, %s)",
100			ctx, NP(parent), interval, NP(community), NP(network)));
101
102	/* are we already discoverying network devices ? */
103	if (snmp_cb_data != NULL) {
104		snmp_cb_data->enabled = FALSE; /* cancel it */
105	}
106
107	/* setup for network device discovery */
108	if ((snmp_cb_data = calloc(1, sizeof (*snmp_cb_data))) != NULL) {
109		snmp_cb_data->ctx = ctx;
110		snmp_cb_data->enabled = TRUE;
111		snmp_cb_data->parent = STRDUP(parent);
112		snmp_cb_data->community = STRDUP(community);
113		snmp_cb_data->network = STRDUP(network);
114
115		/* prime the pump with an initial scan */
116		nds_snmp_scan(ctx, parent, community, network);
117
118		/* add a regular network scan */
119		g_timeout_add(interval * 1000, nds_snmp_scan_cb, snmp_cb_data);
120	}
121
122	return (0);
123}
124
125static int
126nds_DisablePrinterScanningViaSNMP(LibHalContext *ctx)
127{
128	HAL_DEBUG(("NetworkDiscovery.DisablePrinterScanningViaSNMP(0x%8.8x)", ctx));
129
130	if (snmp_cb_data != NULL)
131		snmp_cb_data->enabled = FALSE;
132	snmp_cb_data = NULL;
133
134	return (0);
135}
136
137static int
138nds_ScanForPrintersViaSNMP(LibHalContext *ctx, char *parent, char *community,
139		char *network)
140{
141	time_t start, stop;
142
143	HAL_DEBUG(("NetworkDiscovery.ScanForPrintersViaSNMP(0x%8.8x, %s, %s, %s)",
144			ctx, NP(parent), NP(community), NP(network)));
145
146	return (nds_snmp_scan(ctx, parent, community, network));
147}
148
149static DBusHandlerResult
150nds_filter_function(DBusConnection *connection, DBusMessage *message,
151		void *user_data)
152{
153	LibHalContext *ctx = user_data;
154	DBusMessage *reply;
155	DBusError error;
156	const char *member = dbus_message_get_member(message);
157	const char *path = dbus_message_get_path(message);
158	int rc = -1;
159
160	dbus_error_init(&error);
161
162	HAL_DEBUG(("DBus message: %s, %s ", member, path));
163
164	if (dbus_message_is_method_call(message,
165				DBUS_INTERFACE, "EnablePrinterScanningViaSNMP")) {
166		int interval = -1;
167		char *udi = getenv("UDI");
168		char *community = "public";
169		char *network = "0.0.0.0";
170
171		dbus_message_get_args(message, &error,
172				DBUS_TYPE_INT32, &interval,
173				DBUS_TYPE_STRING, &community,
174				DBUS_TYPE_STRING, &network,
175				DBUS_TYPE_INVALID);
176
177		if (strcmp(network, "0.0.0.0") == 0)
178			network = NULL;
179
180		rc = nds_EnablePrinterScanningViaSNMP(ctx, udi, interval,
181				community, network);
182	} else if (dbus_message_is_method_call(message,
183				DBUS_INTERFACE, "ScanForPrintersViaSNMP")) {
184		int interval = -1;
185		char *udi = getenv("UDI");
186		char *community = "public";
187		char *network = "0.0.0.0";
188
189		dbus_message_get_args(message, &error,
190				DBUS_TYPE_STRING, &community,
191				DBUS_TYPE_STRING, &network,
192				DBUS_TYPE_INVALID);
193
194		if (strcmp(network, "0.0.0.0") == 0)
195			network = NULL;
196
197		rc = nds_ScanForPrintersViaSNMP(ctx, udi, community, network);
198	} else if (dbus_message_is_method_call(message,
199				DBUS_INTERFACE, "DisablePrinterScanningViaSNMP")) {
200		rc = nds_DisablePrinterScanningViaSNMP(ctx);
201	} else
202		HAL_WARNING(("Unknown DBus message: %s, %s ", member, path));
203
204	if (dbus_error_is_set(&error))
205		dbus_error_free(&error);
206
207	if ((reply = dbus_message_new_method_return(message)) == NULL) {
208		HAL_WARNING(("Could not allocate memory for the DBus reply"));
209		return (FALSE);
210	}
211
212	dbus_message_append_args(reply, DBUS_TYPE_INT32, &rc,
213			DBUS_TYPE_INVALID);
214
215	if (!dbus_connection_send(connection, reply, NULL)) {
216		HAL_WARNING(("Could not sent reply"));
217	}
218	dbus_connection_flush(connection);
219	dbus_message_unref(reply);
220
221	return (DBUS_HANDLER_RESULT_HANDLED);
222}
223
224static int
225nds_claim_interface(LibHalContext *ctx, char *udi, DBusError *error)
226{
227	DBusConnection *connection;
228	char *interface_xml =
229		"<method name=\"EnablePrinterScanningViaSNMP\">\n"
230		"  <arg name=\"interval\" direction=\"in\" type=\"i\"/>\n"
231		"  <arg name=\"community\" direction=\"in\" type=\"s\"/>\n"
232		"  <arg name=\"network\" direction=\"in\" type=\"s\"/>\n"
233		"  <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n"
234		"</method>\n"
235		"<method name=\"DisablePrinterScanningViaSNMP\">\n"
236		"  <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n"
237		"</method>\n"
238		"<method name=\"ScanForPrintersViaSNMP\">\n"
239		"  <arg name=\"community\" direction=\"in\" type=\"s\"/>\n"
240		"  <arg name=\"network\" direction=\"in\" type=\"s\"/>\n"
241		"  <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n"
242		"</method>\n";
243
244	HAL_DEBUG(("nds_claim_interface(0x%8.8x, %s, 0x%8.8x): %s",
245			ctx, udi, error, DBUS_INTERFACE));
246
247	if ((connection = libhal_ctx_get_dbus_connection(ctx)) == NULL) {
248		HAL_WARNING(("Could not get DBus connection"));
249		return (-1);
250	}
251
252	if (libhal_device_claim_interface(ctx, udi,
253			DBUS_INTERFACE, interface_xml, error) == 0) {
254		HAL_WARNING(("Could not claim interface: %s", error->message));
255		return (-1);
256	}
257
258	dbus_connection_setup_with_g_main(connection, NULL);
259	dbus_connection_add_filter(connection, nds_filter_function, ctx, NULL);
260	dbus_connection_set_exit_on_disconnect(connection, 0);
261
262	return (0);
263}
264
265static void
266drop_privileges()
267{
268	priv_set_t *pPrivSet = NULL;
269	priv_set_t *lPrivSet = NULL;
270
271	/*
272	 * Start with the 'basic' privilege set and then remove any
273	 * of the 'basic' privileges that will not be needed.
274	 */
275	if ((pPrivSet = priv_str_to_set("basic", ",", NULL)) == NULL) {
276		return;
277	}
278
279	/* Clear privileges we will not need from the 'basic' set */
280	(void) priv_delset(pPrivSet, PRIV_FILE_LINK_ANY);
281	(void) priv_delset(pPrivSet, PRIV_PROC_EXEC);
282	(void) priv_delset(pPrivSet, PRIV_PROC_FORK);
283	(void) priv_delset(pPrivSet, PRIV_PROC_INFO);
284	(void) priv_delset(pPrivSet, PRIV_PROC_SESSION);
285
286	/* Set the permitted privilege set. */
287	if (setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) {
288		return;
289	}
290
291	/* Clear the limit set. */
292	if ((lPrivSet = priv_allocset()) == NULL) {
293		return;
294	}
295
296	priv_emptyset(lPrivSet);
297
298	if (setppriv(PRIV_SET, PRIV_LIMIT, lPrivSet) != 0) {
299		return;
300	}
301
302	priv_freeset(lPrivSet);
303}
304
305
306int
307main(int argc, char **argv)
308{
309	LibHalContext *ctx = NULL;
310	DBusError error;
311	GMainLoop *loop = g_main_loop_new(NULL, FALSE);
312	char *udi;
313
314	if ((udi = getenv("UDI")) == NULL) {
315		return (0);
316	}
317
318	drop_privileges();
319
320	setup_logger();
321
322	dbus_error_init(&error);
323
324	if ((ctx = libhal_ctx_init_direct(&error)) == NULL) {
325		return (0);
326	}
327
328	if (!libhal_device_addon_is_ready(ctx, udi, &error)) {
329		return (0);
330	}
331
332	if (nds_claim_interface(ctx, udi, &error) != 0) {
333		return (0);
334	}
335
336	g_main_loop_run(loop);
337
338	/* NOTREACHED */
339}
340