gboolean address_seems_public (GInetAddress *addr) { return (g_inet_address_get_is_loopback (addr) == FALSE && g_inet_address_get_is_site_local (addr) == FALSE && g_inet_address_get_is_multicast (addr) == FALSE && g_inet_address_get_is_mc_link_local (addr) == FALSE && g_inet_address_get_is_mc_node_local (addr) == FALSE && g_inet_address_get_is_mc_site_local (addr) == FALSE && g_inet_address_get_is_mc_org_local (addr) == FALSE && g_inet_address_get_is_mc_global (addr) == FALSE); }
static gboolean on_socket_input (GSocket *socket, GIOCondition condition, gpointer user_data) { CockpitRequest *request = user_data; guchar first_byte; GInputVector vector[1] = { { &first_byte, 1 } }; gint flags = G_SOCKET_MSG_PEEK; gboolean redirect_tls; gboolean is_tls; GSocketAddress *addr; GInetAddress *inet; GError *error = NULL; GIOStream *tls_stream; gssize num_read; num_read = g_socket_receive_message (socket, NULL, /* out GSocketAddress */ vector, 1, NULL, /* out GSocketControlMessage */ NULL, /* out num_messages */ &flags, NULL, /* GCancellable* */ &error); if (num_read < 0) { /* Just wait and try again */ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { g_error_free (error); return TRUE; } if (!should_suppress_request_error (error)) g_warning ("couldn't read from socket: %s", error->message); cockpit_request_finish (request); g_error_free (error); return FALSE; } is_tls = TRUE; redirect_tls = FALSE; /* * TLS streams are guaranteed to start with octet 22.. this way we can distinguish them * from regular HTTP requests */ if (first_byte != 22 && first_byte != 0x80) { is_tls = FALSE; redirect_tls = TRUE; addr = g_socket_connection_get_remote_address (G_SOCKET_CONNECTION (request->io), NULL); if (G_IS_INET_SOCKET_ADDRESS (addr)) { inet = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr)); redirect_tls = !g_inet_address_get_is_loopback (inet); } g_clear_object (&addr); } if (is_tls) { tls_stream = g_tls_server_connection_new (request->io, request->web_server->certificate, &error); if (tls_stream == NULL) { g_warning ("couldn't create new TLS stream: %s", error->message); cockpit_request_finish (request); g_error_free (error); return FALSE; } g_object_unref (request->io); request->io = G_IO_STREAM (tls_stream); } else if (redirect_tls) { request->delayed_reply = 301; } start_request_input (request); /* No longer run *this* source */ return FALSE; }
static gboolean handler (GThreadedSocketService *service, GSocketConnection *connection, GSocketListener *listener, gpointer user_data) { GLibJsonRpcServerPrivate *jsonrpc_server = (GLibJsonRpcServerPrivate*)user_data; GError *error = NULL; // Check if it is a local connection. - This doesn't work! GSocketAddress *sockaddr = g_socket_connection_get_remote_address(connection, &error); GInetAddress *addr = g_inet_socket_address_get_address(G_INET_SOCKET_ADDRESS(sockaddr)); if (!jsonrpc_server->allow_non_loopback_connections) { #if 0 // Why doesn't this work? if (!g_inet_address_get_is_loopback(addr)) return TRUE; // just fail #endif gchar *addr_string = g_inet_address_to_string(addr); gboolean is_local = g_strstr_len(addr_string, -1, "127.0.0.1") != NULL; g_free(addr_string); if (!is_local) return TRUE; // silently fail } GOutputStream *out; GInputStream *in; char buffer[1024]; gssize size; out = g_io_stream_get_output_stream (G_IO_STREAM (connection)); in = g_io_stream_get_input_stream (G_IO_STREAM (connection)); // Read the http header gboolean skip_header = TRUE; JsonParser *parser = json_parser_new(); GString *json_string = g_string_new(""); while (0 < (size = g_input_stream_read (in, buffer, sizeof buffer, NULL, NULL))) { int header_size = 0; if (skip_header) { gchar *head_end = g_strstr_len(buffer, size, "\r\n\r\n"); if (head_end > 0) header_size = head_end - buffer; else continue; } g_string_append_len(json_string, buffer+header_size, size-header_size); if (json_parser_load_from_data(parser, json_string->str, -1, &error)) break; else g_error_free(error); } // TBD: raise error if there was a syntax error g_string_free(json_string, TRUE); // Get params object without the reader JsonNode *root = json_parser_get_root(parser); JsonObject *root_object = json_node_get_object(root); JsonNode* params = json_object_get_member(root_object, "params"); // Use reader for method and id JsonReader *reader = json_reader_new(json_parser_get_root(parser)); json_reader_read_member (reader, "method"); const gchar *method = json_reader_get_string_value (reader); json_reader_end_member (reader); json_reader_read_member (reader, "id"); gint64 id = json_reader_get_int_value(reader); json_reader_end_member (reader); // Build the response which is either a response object or an error object JsonNode *response = NULL; /* Call the callback */ command_hash_value_t *command_val = NULL; if (method) command_val = g_hash_table_lookup(jsonrpc_server->command_hash, method); if (!command_val) response = create_fault_msg_response(-2, "No such method!",id); else if (command_val->async_callback) { if (jsonrpc_server->async_busy) response = create_fault_msg_response(-2, "Busy!",id); else { // With the embedding of the mutex in the query we should // be able to handle more than one connection, so there // is no need to protect against a busy state. // jsonrpc_server->async_busy = TRUE; GLibJsonRpcAsyncQueryPrivate *query = glib_jsonrpc_server_query_new((GLibJsonRpcServer*)jsonrpc_server); // Create a secondary main loop (*command_val->async_callback)((GLibJsonRpcServer*)jsonrpc_server, (GLibJsonRpcAsyncQuery*)query, method, params, command_val->user_data); // Lock on a mutex g_mutex_lock(&query->mutex); g_cond_wait(&query->cond, &query->mutex); g_mutex_unlock(&query->mutex); if (query->error_num != 0) response = create_fault_value_response(query->error_num,query->reply,id); else response = create_response(query->reply, id); jsonrpc_server->async_busy = FALSE; // Erase the query glib_jsonrpc_async_query_free(query); } } else { JsonNode *reply; int ret = (*command_val->callback)((GLibJsonRpcServer*)jsonrpc_server, method, params, &reply, command_val->user_data); if (ret == 0) response = create_response(reply,id); else // For faults expect a string response containing the error response = create_fault_value_response(ret, reply,id); if (reply) json_node_free(reply); } if (response) { GString *response_string = g_string_new(""); // Serialize response into content_string JsonGenerator *gen = json_generator_new (); gsize len; json_generator_set_root (gen, response); json_node_free(response); gchar *content_string = json_generator_to_data(gen, &len); g_object_unref (gen); g_string_append_printf(response_string, "HTTP/1.1 200 OK\r\n" "Connection: close\r\n" "Content-Length: %d\r\n" "Content-Type: text/xml\r\n" "Date: Fri, 1 Jan 2000 00:00:00 GMT\r\n" "Server: GlibJsonRPC server\r\n" "\r\n" "%s", (int)len, content_string ); g_free(content_string); g_output_stream_write (out, response_string->str, response_string->len, NULL,NULL); g_string_free(response_string, TRUE); } g_object_unref(parser); return TRUE; }