/* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Licensed under the Academic Free License version 2.1 */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "../../hald/logger.h" #include "network-discovery.h" #include "printer.h" #define DBUS_INTERFACE "org.freedesktop.Hal.Device.NetworkDiscovery" #define NP(x) (x?x:"NULL") #define STRDUP(x) (x?strdup(x):NULL) typedef struct { LibHalContext *ctx; gboolean enabled; char *parent; char *community; char *network; } nds_snmp_cbdata_t; static nds_snmp_cbdata_t *snmp_cb_data = NULL; static int nds_snmp_scan(LibHalContext *ctx, char *parent, char *community, char *network) { time_t start; HAL_DEBUG(("nds_snmp_scan(0x%8.8x, %s, %s, %s)", ctx, NP(parent), NP(community), NP(network))); HAL_DEBUG(("NetworkDiscovery snmp scan initated")); /* scan for devices */ time(&start); if (network == NULL) { GList *elem, *list = broadcast_addresses(); for (elem = list; elem != NULL; elem = g_list_next(elem)) { scan_for_devices_using_snmp(ctx, parent, community, (char *)elem->data); free(elem->data); } g_list_free(list); } else scan_for_devices_using_snmp(ctx, parent, community, network); /* remove devices that haven't been seen since before this scan */ scan_for_stale_devices(ctx, start); HAL_DEBUG(("NetworkDiscovery snmp scan completed")); return (0); } static gboolean nds_snmp_scan_cb(gpointer data) { nds_snmp_cbdata_t *args = data; if (args->enabled == FALSE) { if (args->parent) free(args->parent); if (args->community) free(args->community); if (args->network) free(args->network); free(args); return (FALSE); } nds_snmp_scan(args->ctx, args->parent, args->community, args->network); return (TRUE); } static int nds_EnablePrinterScanningViaSNMP(LibHalContext *ctx, char *parent, int interval, char *community, char *network) { HAL_DEBUG(("NetworkDiscovery.EnablePrinterScanningViaSNMP(0x%8.8x, %s, %d, %s, %s)", ctx, NP(parent), interval, NP(community), NP(network))); /* are we already discoverying network devices ? */ if (snmp_cb_data != NULL) { snmp_cb_data->enabled = FALSE; /* cancel it */ } /* setup for network device discovery */ if ((snmp_cb_data = calloc(1, sizeof (*snmp_cb_data))) != NULL) { snmp_cb_data->ctx = ctx; snmp_cb_data->enabled = TRUE; snmp_cb_data->parent = STRDUP(parent); snmp_cb_data->community = STRDUP(community); snmp_cb_data->network = STRDUP(network); /* prime the pump with an initial scan */ nds_snmp_scan(ctx, parent, community, network); /* add a regular network scan */ g_timeout_add(interval * 1000, nds_snmp_scan_cb, snmp_cb_data); } return (0); } static int nds_DisablePrinterScanningViaSNMP(LibHalContext *ctx) { HAL_DEBUG(("NetworkDiscovery.DisablePrinterScanningViaSNMP(0x%8.8x)", ctx)); if (snmp_cb_data != NULL) snmp_cb_data->enabled = FALSE; snmp_cb_data = NULL; return (0); } static int nds_ScanForPrintersViaSNMP(LibHalContext *ctx, char *parent, char *community, char *network) { time_t start, stop; HAL_DEBUG(("NetworkDiscovery.ScanForPrintersViaSNMP(0x%8.8x, %s, %s, %s)", ctx, NP(parent), NP(community), NP(network))); return (nds_snmp_scan(ctx, parent, community, network)); } static DBusHandlerResult nds_filter_function(DBusConnection *connection, DBusMessage *message, void *user_data) { LibHalContext *ctx = user_data; DBusMessage *reply; DBusError error; const char *member = dbus_message_get_member(message); const char *path = dbus_message_get_path(message); int rc = -1; dbus_error_init(&error); HAL_DEBUG(("DBus message: %s, %s ", member, path)); if (dbus_message_is_method_call(message, DBUS_INTERFACE, "EnablePrinterScanningViaSNMP")) { int interval = -1; char *udi = getenv("UDI"); char *community = "public"; char *network = "0.0.0.0"; dbus_message_get_args(message, &error, DBUS_TYPE_INT32, &interval, DBUS_TYPE_STRING, &community, DBUS_TYPE_STRING, &network, DBUS_TYPE_INVALID); if (strcmp(network, "0.0.0.0") == 0) network = NULL; rc = nds_EnablePrinterScanningViaSNMP(ctx, udi, interval, community, network); } else if (dbus_message_is_method_call(message, DBUS_INTERFACE, "ScanForPrintersViaSNMP")) { int interval = -1; char *udi = getenv("UDI"); char *community = "public"; char *network = "0.0.0.0"; dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &community, DBUS_TYPE_STRING, &network, DBUS_TYPE_INVALID); if (strcmp(network, "0.0.0.0") == 0) network = NULL; rc = nds_ScanForPrintersViaSNMP(ctx, udi, community, network); } else if (dbus_message_is_method_call(message, DBUS_INTERFACE, "DisablePrinterScanningViaSNMP")) { rc = nds_DisablePrinterScanningViaSNMP(ctx); } else { /* bypass not-handled messages */ HAL_WARNING(("Unknown DBus message: %s, %s ", member, path)); return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); } if (dbus_error_is_set(&error)) dbus_error_free(&error); if ((reply = dbus_message_new_method_return(message)) == NULL) { HAL_WARNING(("Could not allocate memory for the DBus reply")); return (FALSE); } dbus_message_append_args(reply, DBUS_TYPE_INT32, &rc, DBUS_TYPE_INVALID); if (!dbus_connection_send(connection, reply, NULL)) { HAL_WARNING(("Could not sent reply")); } dbus_connection_flush(connection); dbus_message_unref(reply); return (DBUS_HANDLER_RESULT_HANDLED); } static int nds_claim_interface(LibHalContext *ctx, char *udi, DBusError *error) { DBusConnection *connection; char *interface_xml = "\n" " \n" " \n" " \n" " \n" "\n" "\n" " \n" "\n" "\n" " \n" " \n" " \n" "\n"; HAL_DEBUG(("nds_claim_interface(0x%8.8x, %s, 0x%8.8x): %s", ctx, udi, error, DBUS_INTERFACE)); if ((connection = libhal_ctx_get_dbus_connection(ctx)) == NULL) { HAL_WARNING(("Could not get DBus connection")); return (-1); } if (libhal_device_claim_interface(ctx, udi, DBUS_INTERFACE, interface_xml, error) == 0) { HAL_WARNING(("Could not claim interface: %s", error->message)); return (-1); } dbus_connection_setup_with_g_main(connection, NULL); dbus_connection_add_filter(connection, nds_filter_function, ctx, NULL); dbus_connection_set_exit_on_disconnect(connection, 0); return (0); } static void drop_privileges() { priv_set_t *pPrivSet = NULL; priv_set_t *lPrivSet = NULL; /* * Start with the 'basic' privilege set and then remove any * of the 'basic' privileges that will not be needed. */ if ((pPrivSet = priv_str_to_set("basic", ",", NULL)) == NULL) { return; } /* Clear privileges we will not need from the 'basic' set */ (void) priv_delset(pPrivSet, PRIV_FILE_LINK_ANY); (void) priv_delset(pPrivSet, PRIV_PROC_EXEC); (void) priv_delset(pPrivSet, PRIV_PROC_FORK); (void) priv_delset(pPrivSet, PRIV_PROC_INFO); (void) priv_delset(pPrivSet, PRIV_PROC_SESSION); /* Set the permitted privilege set. */ if (setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) { return; } /* Clear the limit set. */ if ((lPrivSet = priv_allocset()) == NULL) { return; } priv_emptyset(lPrivSet); if (setppriv(PRIV_SET, PRIV_LIMIT, lPrivSet) != 0) { return; } priv_freeset(lPrivSet); } int main(int argc, char **argv) { LibHalContext *ctx = NULL; DBusError error; GMainLoop *loop = g_main_loop_new(NULL, FALSE); char *udi; if ((udi = getenv("UDI")) == NULL) { return (0); } drop_privileges(); setup_logger(); dbus_error_init(&error); if ((ctx = libhal_ctx_init_direct(&error)) == NULL) { return (0); } if (!libhal_device_addon_is_ready(ctx, udi, &error)) { return (0); } if (nds_claim_interface(ctx, udi, &error) != 0) { return (0); } g_main_loop_run(loop); /* NOTREACHED */ }