xref: /illumos-gate/usr/src/cmd/hal/addons/network-devices/addon-network-discovery.c (revision 7800901e60d340b6af88e94a2149805dcfcaaf56)
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 
36 typedef struct {
37 	LibHalContext *ctx;
38 	gboolean enabled;
39 	char *parent;
40 	char *community;
41 	char *network;
42 } nds_snmp_cbdata_t;
43 
44 static nds_snmp_cbdata_t *snmp_cb_data = NULL;
45 
46 static int
47 nds_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 
77 static gboolean
78 nds_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 
95 static int
96 nds_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 
125 static int
126 nds_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 
137 static int
138 nds_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 
149 static DBusHandlerResult
150 nds_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 
224 static int
225 nds_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 
265 static void
266 drop_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 
306 int
307 main(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