remove unused header
[poetteringd.git] / hostnamed.c
blobf327d8205e3d8005f4dc0d53a7881bd304d1ecc5
1 /*
2 Copyright 2020 Robert Nagy
4 Copyright 2012 Alexandre Rostovtsev
6 Some parts are based on the code from the systemd project; these are
7 copyright 2011 Lennart Poettering and others.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include <errno.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
29 #include <dbus/dbus-protocol.h>
30 #include <glib.h>
31 #include <gio/gio.h>
32 #include <polkit/polkit.h>
34 #include "hostnamed.h"
35 #include "hostname1-generated.h"
36 #include "main.h"
37 #include "utils.h"
39 #define QUOTE(macro) #macro
40 #define STR(macro) QUOTE(macro)
42 struct invoked_name {
43 GDBusMethodInvocation *invocation;
44 gchar *name; /* newly allocated */
47 static guint bus_id = 0;
48 static gboolean read_only = FALSE;
50 static PoetteringdHostnamedHostname1 *hostname1 = NULL;
52 static gchar *hostname = NULL;
53 G_LOCK_DEFINE_STATIC (hostname);
54 static gchar *static_hostname = NULL;
55 G_LOCK_DEFINE_STATIC (static_hostname);
56 static gchar *pretty_hostname = NULL;
57 G_LOCK_DEFINE_STATIC (pretty_hostname);
58 static gchar *static_hostname_filename = NULL;
59 static gchar *pretty_hostname_filename = NULL;
60 static gchar *icon_name = NULL;
61 G_LOCK_DEFINE_STATIC (icon_name);
62 static gchar *icon_name_filename = NULL;
64 static gboolean
65 hostname_is_valid (const gchar *name)
67 if (name == NULL)
68 return FALSE;
70 return g_regex_match_simple ("^[a-zA-Z0-9_.-]{1," STR(HOST_NAME_MAX) "}$",
71 name, G_REGEX_MULTILINE, 0);
74 static void
75 on_handle_set_hostname_authorized_cb(GObject *source_object,
76 GAsyncResult *res,
77 gpointer user_data)
79 GError *err = NULL;
80 struct invoked_name *data;
82 data = (struct invoked_name *) user_data;
83 if (!check_polkit_finish (res, &err)) {
84 g_dbus_method_invocation_return_gerror (data->invocation, err);
85 goto out;
88 G_LOCK (hostname);
89 /* Don't allow an empty or invalid hostname */
90 if (!hostname_is_valid (data->name)) {
91 if (data->name != NULL)
92 g_free (data->name);
94 if (hostname_is_valid (static_hostname))
95 data->name = g_strdup (static_hostname);
96 else
97 data->name = g_strdup ("localhost");
99 if (sethostname (data->name, strlen(data->name))) {
100 int errsv = errno;
101 g_dbus_method_invocation_return_dbus_error (data->invocation,
102 DBUS_ERROR_FAILED,
103 strerror (errsv));
104 G_UNLOCK (hostname);
105 goto out;
107 g_free (hostname);
108 hostname = data->name; /* data->name is g_strdup-ed already */;
109 poetteringd_hostnamed_hostname1_complete_set_hostname (hostname1, data->invocation);
110 poetteringd_hostnamed_hostname1_set_hostname (hostname1, hostname);
111 G_UNLOCK (hostname);
113 out:
114 g_free (data);
115 if (err != NULL)
116 g_error_free (err);
119 static gboolean
120 on_handle_set_hostname (PoetteringdHostnamedHostname1 *hostname1,
121 GDBusMethodInvocation *invocation,
122 const gchar *name,
123 const gboolean user_interaction,
124 gpointer user_data)
126 if (read_only)
127 g_dbus_method_invocation_return_dbus_error (invocation,
128 DBUS_ERROR_NOT_SUPPORTED,
129 "poetteringd hostnamed is in read-only mode");
130 else {
131 struct invoked_name *data;
132 data = g_new0 (struct invoked_name, 1);
133 data->invocation = invocation;
134 data->name = g_strdup (name);
135 check_polkit_async (g_dbus_method_invocation_get_sender (invocation),
136 "org.freedesktop.hostname1.set-hostname", user_interaction,
137 on_handle_set_hostname_authorized_cb, data);
140 return TRUE;
143 static void
144 on_handle_set_static_hostname_authorized_cb (GObject *source_object,
145 GAsyncResult *res,
146 gpointer user_data)
148 GError *err = NULL;
149 struct invoked_name *data = (struct invoked_name *) user_data;
150 gchar *fixed_hostname = NULL;
151 gint fnlen;
153 G_LOCK (static_hostname);
155 if (!check_polkit_finish (res, &err)) {
156 g_dbus_method_invocation_return_gerror (data->invocation, err);
157 goto out;
160 /* Don't allow an empty or invalid hostname */
161 if (!hostname_is_valid (data->name)) {
162 if (data->name != NULL)
163 g_free (data->name);
165 data->name = g_strdup ("localhost");
168 /* myname(5) requires a newline at the end */
169 fixed_hostname = g_strdup(data->name);
170 fnlen = strlen(fixed_hostname);
171 if (fixed_hostname[fnlen - 1] != '\n') {
172 strcat(fixed_hostname, "\n");
173 fnlen++;
176 if (!g_file_set_contents_full(static_hostname_filename, fixed_hostname, fnlen,
177 G_FILE_SET_CONTENTS_CONSISTENT, 0644, &err)) {
178 g_dbus_method_invocation_return_gerror (data->invocation, err);
179 goto out;
182 G_LOCK (hostname);
183 if (sethostname (data->name, strlen(data->name))) {
184 int errsv = errno;
185 g_dbus_method_invocation_return_dbus_error (data->invocation,
186 DBUS_ERROR_FAILED,
187 strerror (errsv));
188 G_UNLOCK (hostname);
189 goto out;
191 g_free (hostname);
192 hostname = data->name; /* data->name is g_strdup-ed already */;
193 G_UNLOCK (hostname);
195 g_free (static_hostname);
196 static_hostname = data->name; /* data->name is g_strdup-ed already */;
197 poetteringd_hostnamed_hostname1_complete_set_static_hostname (hostname1, data->invocation);
198 poetteringd_hostnamed_hostname1_set_static_hostname (hostname1, static_hostname);
200 out:
201 G_UNLOCK (static_hostname);
202 g_free (fixed_hostname);
203 g_free (data);
204 if (err != NULL)
205 g_error_free (err);
208 static gboolean
209 on_handle_set_static_hostname (PoetteringdHostnamedHostname1 *hostname1,
210 GDBusMethodInvocation *invocation,
211 const gchar *name,
212 const gboolean user_interaction,
213 gpointer user_data)
215 if (read_only)
216 g_dbus_method_invocation_return_dbus_error (invocation,
217 DBUS_ERROR_NOT_SUPPORTED,
218 "poetteringd hostnamed is in read-only mode");
219 else {
220 struct invoked_name *data;
221 data = g_new0 (struct invoked_name, 1);
222 data->invocation = invocation;
223 data->name = g_strdup (name);
224 check_polkit_async (g_dbus_method_invocation_get_sender (invocation), "org.freedesktop.hostname1.set-static-hostname", user_interaction, on_handle_set_static_hostname_authorized_cb, data);
227 return TRUE; /* Always return TRUE to indicate signal has been handled */
230 static void
231 on_handle_set_pretty_hostname_authorized_cb (GObject *source_object,
232 GAsyncResult *res,
233 gpointer user_data)
235 GError *err = NULL;
236 struct invoked_name *data = (struct invoked_name *) user_data;
238 G_LOCK (pretty_hostname);
240 if (!check_polkit_finish (res, &err)) {
241 g_dbus_method_invocation_return_gerror (data->invocation, err);
242 goto out;
245 /* Don't allow a null pretty hostname */
246 if (data->name == NULL)
247 data->name = g_strdup ("");
249 if (!g_file_set_contents_full(pretty_hostname_filename, data->name, strlen(data->name),
250 G_FILE_SET_CONTENTS_CONSISTENT, 0644, &err)) {
251 g_dbus_method_invocation_return_gerror (data->invocation, err);
252 goto out;
255 g_free (pretty_hostname);
256 pretty_hostname = data->name; /* data->name is g_strdup-ed already */
257 poetteringd_hostnamed_hostname1_complete_set_pretty_hostname (hostname1, data->invocation);
258 poetteringd_hostnamed_hostname1_set_pretty_hostname (hostname1, pretty_hostname);
260 out:
261 G_UNLOCK (pretty_hostname);
262 g_free (data);
263 if (err != NULL)
264 g_error_free (err);
267 static gboolean
268 on_handle_set_pretty_hostname (PoetteringdHostnamedHostname1 *hostname1,
269 GDBusMethodInvocation *invocation,
270 const gchar *name,
271 const gboolean user_interaction,
272 gpointer user_data)
274 if (read_only)
275 g_dbus_method_invocation_return_dbus_error (invocation,
276 DBUS_ERROR_NOT_SUPPORTED,
277 "poetteringd hostnamed is in read-only mode");
278 else {
279 struct invoked_name *data;
280 data = g_new0 (struct invoked_name, 1);
281 data->invocation = invocation;
282 data->name = g_strdup (name);
283 check_polkit_async (g_dbus_method_invocation_get_sender (invocation),
284 "org.freedesktop.hostname1.set-machine-info",
285 user_interaction, on_handle_set_pretty_hostname_authorized_cb, data);
288 return TRUE; /* Always return TRUE to indicate signal has been handled */
291 static void
292 on_handle_set_icon_name_authorized_cb (GObject *source_object,
293 GAsyncResult *res,
294 gpointer user_data)
296 GError *err = NULL;
297 struct invoked_name *data = (struct invoked_name *) user_data;
299 if (!check_polkit_finish (res, &err)) {
300 g_dbus_method_invocation_return_gerror (data->invocation, err);
301 goto out;
304 G_LOCK (icon_name);
306 /* Don't allow a null pretty hostname */
307 if (data->name == NULL)
308 data->name = g_strdup ("");
310 if (!g_file_set_contents_full(icon_name_filename, data->name, strlen(data->name),
311 G_FILE_SET_CONTENTS_CONSISTENT, 0644, &err)) {
312 g_dbus_method_invocation_return_gerror (data->invocation, err);
313 G_UNLOCK (icon_name);
314 goto out;
317 g_free (icon_name);
318 icon_name = data->name; /* data->name is g_strdup-ed already */
319 poetteringd_hostnamed_hostname1_complete_set_icon_name (hostname1, data->invocation);
320 poetteringd_hostnamed_hostname1_set_icon_name (hostname1, icon_name);
322 G_UNLOCK (icon_name);
324 out:
325 g_free (data);
326 if (err != NULL)
327 g_error_free (err);
330 static gboolean
331 on_handle_set_icon_name (PoetteringdHostnamedHostname1 *hostname1,
332 GDBusMethodInvocation *invocation,
333 const gchar *name,
334 const gboolean user_interaction,
335 gpointer user_data)
337 if (read_only)
338 g_dbus_method_invocation_return_dbus_error (invocation,
339 DBUS_ERROR_NOT_SUPPORTED,
340 "poetteringd hostnamed is in read-only mode");
341 else {
342 struct invoked_name *data;
343 data = g_new0 (struct invoked_name, 1);
344 data->invocation = invocation;
345 data->name = g_strdup (name);
346 check_polkit_async (g_dbus_method_invocation_get_sender (invocation), "org.freedesktop.hostname1.set-machine-info", user_interaction, on_handle_set_icon_name_authorized_cb, data);
349 return TRUE; /* Always return TRUE to indicate signal has been handled */
352 static void
353 on_bus_acquired (GDBusConnection *connection,
354 const gchar *bus_name,
355 gpointer user_data)
357 GError *err = NULL;
359 g_debug ("Acquired a message bus connection");
361 hostname1 = poetteringd_hostnamed_hostname1_skeleton_new ();
363 poetteringd_hostnamed_hostname1_set_hostname (hostname1, hostname);
364 poetteringd_hostnamed_hostname1_set_static_hostname (hostname1, static_hostname);
365 poetteringd_hostnamed_hostname1_set_pretty_hostname (hostname1, pretty_hostname);
366 poetteringd_hostnamed_hostname1_set_icon_name (hostname1, icon_name);
368 g_signal_connect (hostname1, "handle-set-hostname", G_CALLBACK (on_handle_set_hostname), NULL);
369 g_signal_connect (hostname1, "handle-set-static-hostname", G_CALLBACK (on_handle_set_static_hostname), NULL);
370 g_signal_connect (hostname1, "handle-set-pretty-hostname", G_CALLBACK (on_handle_set_pretty_hostname), NULL);
371 g_signal_connect (hostname1, "handle-set-icon-name", G_CALLBACK (on_handle_set_icon_name), NULL);
373 if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (hostname1),
374 connection,
375 "/org/freedesktop/hostname1",
376 &err)) {
377 if (err != NULL) {
378 g_critical ("Failed to export interface on /org/freedesktop/hostname1: %s", err->message);
379 poetteringd_exit (1);
384 static void
385 on_name_acquired (GDBusConnection *connection,
386 const gchar *bus_name,
387 gpointer user_data)
389 g_debug ("Acquired the name %s", bus_name);
390 poetteringd_component_started ();
393 static void
394 on_name_lost (GDBusConnection *connection,
395 const gchar *bus_name,
396 gpointer user_data)
398 if (connection == NULL)
399 g_critical ("Failed to acquire a dbus connection");
400 else
401 g_critical ("Failed to acquire dbus name %s", bus_name);
403 poetteringd_exit (1);
406 /* Public functions */
408 void
409 hostnamed_init (gboolean _read_only)
411 gint len;
412 GError *err = NULL;
414 hostname = g_malloc0 (HOST_NAME_MAX + 1);
415 if (gethostname (hostname, HOST_NAME_MAX)) {
416 perror (NULL);
417 g_strlcpy (hostname, "localhost", HOST_NAME_MAX + 1);
420 static_hostname_filename = g_build_filename (SYSCONFDIR "/myname", NULL);
421 g_file_get_contents (static_hostname_filename, &static_hostname, NULL, &err);
422 if (err != NULL) {
423 g_debug ("%s", err->message);
424 g_error_free (err);
425 err = NULL;
427 len = strlen(static_hostname);
428 if (len > 0 && static_hostname[len - 1] == '\n')
429 static_hostname[len - 1] = '\0';
431 pretty_hostname_filename = g_build_filename (SYSCONFDIR "/myprettyname", NULL);
432 g_file_get_contents (pretty_hostname_filename, &pretty_hostname, NULL, &err);
433 if (err != NULL) {
434 g_debug ("%s", err->message);
435 g_error_free (err);
436 err = NULL;
437 pretty_hostname = g_strdup(hostname);
438 } else {
439 len = strlen(pretty_hostname);
440 if (len > 0 && pretty_hostname[len - 1] == '\n')
441 pretty_hostname[len - 1] = '\0';
444 icon_name_filename = g_build_filename (SYSCONFDIR "/myiconname", NULL);
445 g_file_get_contents (icon_name_filename, &icon_name, NULL, &err);
446 if (err != NULL) {
447 g_debug ("%s", err->message);
448 g_error_free (err);
449 err = NULL;
450 icon_name = g_strdup("computer");
451 } else {
452 len = strlen(icon_name);
453 if (len > 0 && icon_name[len - 1] == '\n')
454 icon_name[len - 1] = '\0';
457 read_only = _read_only;
459 bus_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
460 "org.freedesktop.hostname1",
461 G_BUS_NAME_OWNER_FLAGS_NONE,
462 on_bus_acquired,
463 on_name_acquired,
464 on_name_lost,
465 NULL,
466 NULL);
469 void
470 hostnamed_destroy (void)
472 g_bus_unown_name (bus_id);
473 bus_id = 0;
474 read_only = FALSE;
475 g_free (hostname);
476 g_free (static_hostname);
477 g_free (pretty_hostname);
478 g_free (icon_name);