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