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