15307Sjacobs /*
2*10659SXiao-Lin.Zhang@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
35307Sjacobs  * Use is subject to license terms.
45307Sjacobs  *
55307Sjacobs  * Licensed under the Academic Free License version 2.1
65307Sjacobs  */
75307Sjacobs 
85307Sjacobs 
95307Sjacobs #ifdef HAVE_CONFIG_H
105307Sjacobs #include <config.h>
115307Sjacobs #endif
125307Sjacobs 
135307Sjacobs #include <stdio.h>
145307Sjacobs #include <unistd.h>
155307Sjacobs #include <string.h>
165307Sjacobs #include <stdlib.h>
175307Sjacobs #include <fcntl.h>
185307Sjacobs #include <sys/dkio.h>
195307Sjacobs #include <sys/stat.h>
205307Sjacobs #include <priv.h>
215307Sjacobs #include <glib.h>
225307Sjacobs 
235307Sjacobs #include <dbus/dbus-glib-lowlevel.h>
245307Sjacobs #include <libhal.h>
255307Sjacobs 
265307Sjacobs #include "../../hald/logger.h"
275307Sjacobs 
285307Sjacobs #include "network-discovery.h"
295307Sjacobs #include "printer.h"
305307Sjacobs 
315307Sjacobs #define	DBUS_INTERFACE	"org.freedesktop.Hal.Device.NetworkDiscovery"
325307Sjacobs #define	NP(x)	(x?x:"NULL")
335307Sjacobs #define	STRDUP(x)	(x?strdup(x):NULL)
345307Sjacobs 
355307Sjacobs typedef struct {
365307Sjacobs 	LibHalContext *ctx;
375307Sjacobs 	gboolean enabled;
385307Sjacobs 	char *parent;
395307Sjacobs 	char *community;
405307Sjacobs 	char *network;
415307Sjacobs } nds_snmp_cbdata_t;
425307Sjacobs 
435307Sjacobs static nds_snmp_cbdata_t *snmp_cb_data = NULL;
445307Sjacobs 
455307Sjacobs static int
nds_snmp_scan(LibHalContext * ctx,char * parent,char * community,char * network)465307Sjacobs nds_snmp_scan(LibHalContext *ctx, char *parent, char *community, char *network)
475307Sjacobs {
485307Sjacobs 	time_t start;
495307Sjacobs 
505307Sjacobs 	HAL_DEBUG(("nds_snmp_scan(0x%8.8x, %s, %s, %s)",
515307Sjacobs 			ctx, NP(parent), NP(community), NP(network)));
525307Sjacobs 	HAL_DEBUG(("NetworkDiscovery snmp scan initated"));
535307Sjacobs 
545307Sjacobs 	/* scan for devices */
555307Sjacobs 	time(&start);
565307Sjacobs 	if (network == NULL) {
575307Sjacobs 		GList *elem, *list = broadcast_addresses();
585307Sjacobs 
595307Sjacobs 		for (elem = list; elem != NULL; elem = g_list_next(elem)) {
605307Sjacobs 			scan_for_devices_using_snmp(ctx, parent, community,
615307Sjacobs 						(char *)elem->data);
625307Sjacobs 			free(elem->data);
635307Sjacobs 		}
645307Sjacobs 		g_list_free(list);
655307Sjacobs 	} else
665307Sjacobs 		scan_for_devices_using_snmp(ctx, parent, community, network);
675307Sjacobs 
685307Sjacobs 	/* remove devices that haven't been seen since before this scan */
695307Sjacobs 	scan_for_stale_devices(ctx, start);
705307Sjacobs 
715307Sjacobs 	HAL_DEBUG(("NetworkDiscovery snmp scan completed"));
725307Sjacobs 
735307Sjacobs 	return (0);
745307Sjacobs }
755307Sjacobs 
765307Sjacobs static gboolean
nds_snmp_scan_cb(gpointer data)775307Sjacobs nds_snmp_scan_cb(gpointer data)
785307Sjacobs {
795307Sjacobs 	nds_snmp_cbdata_t *args = data;
805307Sjacobs 
815307Sjacobs 	if (args->enabled == FALSE) {
825307Sjacobs 		if (args->parent) free(args->parent);
835307Sjacobs 		if (args->community) free(args->community);
845307Sjacobs 		if (args->network) free(args->network);
855307Sjacobs 		free(args);
865307Sjacobs 		return (FALSE);
875307Sjacobs 	}
885307Sjacobs 
895307Sjacobs 	nds_snmp_scan(args->ctx, args->parent, args->community, args->network);
905307Sjacobs 
915307Sjacobs 	return (TRUE);
925307Sjacobs }
935307Sjacobs 
945307Sjacobs static int
nds_EnablePrinterScanningViaSNMP(LibHalContext * ctx,char * parent,int interval,char * community,char * network)955307Sjacobs nds_EnablePrinterScanningViaSNMP(LibHalContext *ctx, char *parent, int interval,
965307Sjacobs 		char *community, char *network)
975307Sjacobs {
985307Sjacobs 	HAL_DEBUG(("NetworkDiscovery.EnablePrinterScanningViaSNMP(0x%8.8x, %s, %d, %s, %s)",
995307Sjacobs 			ctx, NP(parent), interval, NP(community), NP(network)));
1005307Sjacobs 
1015307Sjacobs 	/* are we already discoverying network devices ? */
1025307Sjacobs 	if (snmp_cb_data != NULL) {
1035307Sjacobs 		snmp_cb_data->enabled = FALSE; /* cancel it */
1045307Sjacobs 	}
1055307Sjacobs 
1065307Sjacobs 	/* setup for network device discovery */
1075307Sjacobs 	if ((snmp_cb_data = calloc(1, sizeof (*snmp_cb_data))) != NULL) {
1085307Sjacobs 		snmp_cb_data->ctx = ctx;
1095307Sjacobs 		snmp_cb_data->enabled = TRUE;
1105307Sjacobs 		snmp_cb_data->parent = STRDUP(parent);
1115307Sjacobs 		snmp_cb_data->community = STRDUP(community);
1125307Sjacobs 		snmp_cb_data->network = STRDUP(network);
1135307Sjacobs 
1145307Sjacobs 		/* prime the pump with an initial scan */
1155307Sjacobs 		nds_snmp_scan(ctx, parent, community, network);
1165307Sjacobs 
1175307Sjacobs 		/* add a regular network scan */
1185307Sjacobs 		g_timeout_add(interval * 1000, nds_snmp_scan_cb, snmp_cb_data);
1195307Sjacobs 	}
1205307Sjacobs 
1215307Sjacobs 	return (0);
1225307Sjacobs }
1235307Sjacobs 
1245307Sjacobs static int
nds_DisablePrinterScanningViaSNMP(LibHalContext * ctx)1255307Sjacobs nds_DisablePrinterScanningViaSNMP(LibHalContext *ctx)
1265307Sjacobs {
1275307Sjacobs 	HAL_DEBUG(("NetworkDiscovery.DisablePrinterScanningViaSNMP(0x%8.8x)", ctx));
1285307Sjacobs 
1295307Sjacobs 	if (snmp_cb_data != NULL)
1305307Sjacobs 		snmp_cb_data->enabled = FALSE;
1315307Sjacobs 	snmp_cb_data = NULL;
1325307Sjacobs 
1335307Sjacobs 	return (0);
1345307Sjacobs }
1355307Sjacobs 
1365307Sjacobs static int
nds_ScanForPrintersViaSNMP(LibHalContext * ctx,char * parent,char * community,char * network)1375307Sjacobs nds_ScanForPrintersViaSNMP(LibHalContext *ctx, char *parent, char *community,
1385307Sjacobs 		char *network)
1395307Sjacobs {
1405307Sjacobs 	time_t start, stop;
1415307Sjacobs 
1425307Sjacobs 	HAL_DEBUG(("NetworkDiscovery.ScanForPrintersViaSNMP(0x%8.8x, %s, %s, %s)",
1435307Sjacobs 			ctx, NP(parent), NP(community), NP(network)));
1445307Sjacobs 
1455307Sjacobs 	return (nds_snmp_scan(ctx, parent, community, network));
1465307Sjacobs }
1475307Sjacobs 
1485307Sjacobs static DBusHandlerResult
nds_filter_function(DBusConnection * connection,DBusMessage * message,void * user_data)1495307Sjacobs nds_filter_function(DBusConnection *connection, DBusMessage *message,
1505307Sjacobs 		void *user_data)
1515307Sjacobs {
1525307Sjacobs 	LibHalContext *ctx = user_data;
1535307Sjacobs 	DBusMessage *reply;
1545307Sjacobs 	DBusError error;
1555307Sjacobs 	const char *member = dbus_message_get_member(message);
1565307Sjacobs 	const char *path = dbus_message_get_path(message);
1575307Sjacobs 	int rc = -1;
1585307Sjacobs 
1595307Sjacobs 	dbus_error_init(&error);
1605307Sjacobs 
1615307Sjacobs 	HAL_DEBUG(("DBus message: %s, %s ", member, path));
1625307Sjacobs 
1635307Sjacobs 	if (dbus_message_is_method_call(message,
1645307Sjacobs 				DBUS_INTERFACE, "EnablePrinterScanningViaSNMP")) {
1655307Sjacobs 		int interval = -1;
1665307Sjacobs 		char *udi = getenv("UDI");
1675307Sjacobs 		char *community = "public";
1685307Sjacobs 		char *network = "0.0.0.0";
1695307Sjacobs 
1705307Sjacobs 		dbus_message_get_args(message, &error,
1715307Sjacobs 				DBUS_TYPE_INT32, &interval,
1725307Sjacobs 				DBUS_TYPE_STRING, &community,
1735307Sjacobs 				DBUS_TYPE_STRING, &network,
1745307Sjacobs 				DBUS_TYPE_INVALID);
1755307Sjacobs 
1765307Sjacobs 		if (strcmp(network, "0.0.0.0") == 0)
1775307Sjacobs 			network = NULL;
1785307Sjacobs 
1795307Sjacobs 		rc = nds_EnablePrinterScanningViaSNMP(ctx, udi, interval,
1805307Sjacobs 				community, network);
1815307Sjacobs 	} else if (dbus_message_is_method_call(message,
1825307Sjacobs 				DBUS_INTERFACE, "ScanForPrintersViaSNMP")) {
1835307Sjacobs 		int interval = -1;
1845307Sjacobs 		char *udi = getenv("UDI");
1855307Sjacobs 		char *community = "public";
1865307Sjacobs 		char *network = "0.0.0.0";
1875307Sjacobs 
1885307Sjacobs 		dbus_message_get_args(message, &error,
1895307Sjacobs 				DBUS_TYPE_STRING, &community,
1905307Sjacobs 				DBUS_TYPE_STRING, &network,
1915307Sjacobs 				DBUS_TYPE_INVALID);
1925307Sjacobs 
1935307Sjacobs 		if (strcmp(network, "0.0.0.0") == 0)
1945307Sjacobs 			network = NULL;
1955307Sjacobs 
1965307Sjacobs 		rc = nds_ScanForPrintersViaSNMP(ctx, udi, community, network);
1975307Sjacobs 	} else if (dbus_message_is_method_call(message,
1985307Sjacobs 				DBUS_INTERFACE, "DisablePrinterScanningViaSNMP")) {
1995307Sjacobs 		rc = nds_DisablePrinterScanningViaSNMP(ctx);
200*10659SXiao-Lin.Zhang@Sun.COM 	} else {
201*10659SXiao-Lin.Zhang@Sun.COM 		/* bypass not-handled messages */
2025307Sjacobs 		HAL_WARNING(("Unknown DBus message: %s, %s ", member, path));
203*10659SXiao-Lin.Zhang@Sun.COM 		return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
204*10659SXiao-Lin.Zhang@Sun.COM 	}
2055307Sjacobs 
2065307Sjacobs 	if (dbus_error_is_set(&error))
2075307Sjacobs 		dbus_error_free(&error);
2085307Sjacobs 
2095307Sjacobs 	if ((reply = dbus_message_new_method_return(message)) == NULL) {
2105307Sjacobs 		HAL_WARNING(("Could not allocate memory for the DBus reply"));
2115307Sjacobs 		return (FALSE);
2125307Sjacobs 	}
2135307Sjacobs 
2145307Sjacobs 	dbus_message_append_args(reply, DBUS_TYPE_INT32, &rc,
2155307Sjacobs 			DBUS_TYPE_INVALID);
2165307Sjacobs 
2175307Sjacobs 	if (!dbus_connection_send(connection, reply, NULL)) {
2185307Sjacobs 		HAL_WARNING(("Could not sent reply"));
2195307Sjacobs 	}
2205307Sjacobs 	dbus_connection_flush(connection);
2215307Sjacobs 	dbus_message_unref(reply);
2225307Sjacobs 
2235307Sjacobs 	return (DBUS_HANDLER_RESULT_HANDLED);
2245307Sjacobs }
2255307Sjacobs 
2265307Sjacobs static int
nds_claim_interface(LibHalContext * ctx,char * udi,DBusError * error)2275307Sjacobs nds_claim_interface(LibHalContext *ctx, char *udi, DBusError *error)
2285307Sjacobs {
2295307Sjacobs 	DBusConnection *connection;
2305307Sjacobs 	char *interface_xml =
2315307Sjacobs 		"<method name=\"EnablePrinterScanningViaSNMP\">\n"
2325307Sjacobs 		"  <arg name=\"interval\" direction=\"in\" type=\"i\"/>\n"
2335307Sjacobs 		"  <arg name=\"community\" direction=\"in\" type=\"s\"/>\n"
2345307Sjacobs 		"  <arg name=\"network\" direction=\"in\" type=\"s\"/>\n"
2355307Sjacobs 		"  <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n"
2365307Sjacobs 		"</method>\n"
2375307Sjacobs 		"<method name=\"DisablePrinterScanningViaSNMP\">\n"
2385307Sjacobs 		"  <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n"
2395307Sjacobs 		"</method>\n"
2405307Sjacobs 		"<method name=\"ScanForPrintersViaSNMP\">\n"
2415307Sjacobs 		"  <arg name=\"community\" direction=\"in\" type=\"s\"/>\n"
2425307Sjacobs 		"  <arg name=\"network\" direction=\"in\" type=\"s\"/>\n"
2435307Sjacobs 		"  <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n"
2445307Sjacobs 		"</method>\n";
2455307Sjacobs 
2465307Sjacobs 	HAL_DEBUG(("nds_claim_interface(0x%8.8x, %s, 0x%8.8x): %s",
2475307Sjacobs 			ctx, udi, error, DBUS_INTERFACE));
2485307Sjacobs 
2495307Sjacobs 	if ((connection = libhal_ctx_get_dbus_connection(ctx)) == NULL) {
2505307Sjacobs 		HAL_WARNING(("Could not get DBus connection"));
2515307Sjacobs 		return (-1);
2525307Sjacobs 	}
2535307Sjacobs 
2545307Sjacobs 	if (libhal_device_claim_interface(ctx, udi,
2555307Sjacobs 			DBUS_INTERFACE, interface_xml, error) == 0) {
2565307Sjacobs 		HAL_WARNING(("Could not claim interface: %s", error->message));
2575307Sjacobs 		return (-1);
2585307Sjacobs 	}
2595307Sjacobs 
2605307Sjacobs 	dbus_connection_setup_with_g_main(connection, NULL);
2615307Sjacobs 	dbus_connection_add_filter(connection, nds_filter_function, ctx, NULL);
2625307Sjacobs 	dbus_connection_set_exit_on_disconnect(connection, 0);
2635307Sjacobs 
2645307Sjacobs 	return (0);
2655307Sjacobs }
2665307Sjacobs 
2675307Sjacobs static void
drop_privileges()2685307Sjacobs drop_privileges()
2695307Sjacobs {
2705307Sjacobs 	priv_set_t *pPrivSet = NULL;
2715307Sjacobs 	priv_set_t *lPrivSet = NULL;
2725307Sjacobs 
2735307Sjacobs 	/*
2745307Sjacobs 	 * Start with the 'basic' privilege set and then remove any
2755307Sjacobs 	 * of the 'basic' privileges that will not be needed.
2765307Sjacobs 	 */
2775307Sjacobs 	if ((pPrivSet = priv_str_to_set("basic", ",", NULL)) == NULL) {
2785307Sjacobs 		return;
2795307Sjacobs 	}
2805307Sjacobs 
2815307Sjacobs 	/* Clear privileges we will not need from the 'basic' set */
2825307Sjacobs 	(void) priv_delset(pPrivSet, PRIV_FILE_LINK_ANY);
2835307Sjacobs 	(void) priv_delset(pPrivSet, PRIV_PROC_EXEC);
2845307Sjacobs 	(void) priv_delset(pPrivSet, PRIV_PROC_FORK);
2855307Sjacobs 	(void) priv_delset(pPrivSet, PRIV_PROC_INFO);
2865307Sjacobs 	(void) priv_delset(pPrivSet, PRIV_PROC_SESSION);
2875307Sjacobs 
2885307Sjacobs 	/* Set the permitted privilege set. */
2895307Sjacobs 	if (setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) {
2905307Sjacobs 		return;
2915307Sjacobs 	}
2925307Sjacobs 
2935307Sjacobs 	/* Clear the limit set. */
2945307Sjacobs 	if ((lPrivSet = priv_allocset()) == NULL) {
2955307Sjacobs 		return;
2965307Sjacobs 	}
2975307Sjacobs 
2985307Sjacobs 	priv_emptyset(lPrivSet);
2995307Sjacobs 
3005307Sjacobs 	if (setppriv(PRIV_SET, PRIV_LIMIT, lPrivSet) != 0) {
3015307Sjacobs 		return;
3025307Sjacobs 	}
3035307Sjacobs 
3045307Sjacobs 	priv_freeset(lPrivSet);
3055307Sjacobs }
3065307Sjacobs 
3075307Sjacobs 
3085307Sjacobs int
main(int argc,char ** argv)3095307Sjacobs main(int argc, char **argv)
3105307Sjacobs {
3115307Sjacobs 	LibHalContext *ctx = NULL;
3125307Sjacobs 	DBusError error;
3135307Sjacobs 	GMainLoop *loop = g_main_loop_new(NULL, FALSE);
3145307Sjacobs 	char *udi;
3155307Sjacobs 
3165307Sjacobs 	if ((udi = getenv("UDI")) == NULL) {
3175307Sjacobs 		return (0);
3185307Sjacobs 	}
3195307Sjacobs 
3205307Sjacobs 	drop_privileges();
3215307Sjacobs 
3225307Sjacobs 	setup_logger();
3235307Sjacobs 
3245307Sjacobs 	dbus_error_init(&error);
3255307Sjacobs 
3265307Sjacobs 	if ((ctx = libhal_ctx_init_direct(&error)) == NULL) {
3275307Sjacobs 		return (0);
3285307Sjacobs 	}
3295307Sjacobs 
3305307Sjacobs 	if (!libhal_device_addon_is_ready(ctx, udi, &error)) {
3315307Sjacobs 		return (0);
3325307Sjacobs 	}
3335307Sjacobs 
3345307Sjacobs 	if (nds_claim_interface(ctx, udi, &error) != 0) {
3355307Sjacobs 		return (0);
3365307Sjacobs 	}
3375307Sjacobs 
3385307Sjacobs 	g_main_loop_run(loop);
3395307Sjacobs 
3405307Sjacobs 	/* NOTREACHED */
3415307Sjacobs }
342