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