Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 259634
Collapse All | Expand All

(-)NetworkManager-0.7.1.orig/src/NetworkManagerPolicy.c (-354 lines)
Lines 44-67 Link Here
44
#include "nm-named-manager.h"
44
#include "nm-named-manager.h"
45
#include "nm-vpn-manager.h"
45
#include "nm-vpn-manager.h"
46
46
47
typedef struct LookupThread LookupThread;
48
49
typedef void (*LookupCallback) (LookupThread *thread, gpointer user_data);
50
51
struct LookupThread {
52
	GThread *thread;
53
54
	GMutex *lock;
55
	gboolean die;
56
	int ret;
57
58
	guint32 ip4_addr;
59
	char hostname[NI_MAXHOST + 1];
60
61
	LookupCallback callback;
62
	gpointer user_data;
63
};
64
65
struct NMPolicy {
47
struct NMPolicy {
66
	NMManager *manager;
48
	NMManager *manager;
67
	guint update_state_id;
49
	guint update_state_id;
Lines 74-169 Link Here
74
	gulong vpn_deactivated_id;
56
	gulong vpn_deactivated_id;
75
57
76
	NMDevice *default_device;
58
	NMDevice *default_device;
77
78
	LookupThread *lookup;
79
};
59
};
80
60
81
static gboolean
82
lookup_thread_run_cb (gpointer user_data)
83
{
84
	LookupThread *thread = (LookupThread *) user_data;
85
86
	(*thread->callback) (thread, thread->user_data);
87
	return FALSE;
88
}
89
90
static gpointer
91
lookup_thread_worker (gpointer data)
92
{
93
	LookupThread *thread = (LookupThread *) data;
94
	struct sockaddr_in addr;
95
96
	g_mutex_lock (thread->lock);
97
	if (thread->die) {
98
		g_mutex_unlock (thread->lock);
99
		return (gpointer) NULL;
100
	}
101
	g_mutex_unlock (thread->lock);
102
103
	addr.sin_family = AF_INET;
104
	addr.sin_addr.s_addr = thread->ip4_addr;
105
106
	thread->ret = getnameinfo ((struct sockaddr *) &addr, sizeof (struct sockaddr_in),
107
	                           thread->hostname, NI_MAXHOST, NULL, 0,
108
	                           NI_NAMEREQD);
109
	if (thread->ret == 0) {
110
		int i;
111
112
		for (i = 0; i < strlen (thread->hostname); i++)
113
			thread->hostname[i] = tolower (thread->hostname[i]);
114
	}
115
116
	/* Don't track the idle handler ID because by the time the g_idle_add()
117
	 * returns the ID, the handler may already have run and freed the
118
	 * LookupThread.
119
	 */
120
	g_idle_add (lookup_thread_run_cb, thread);
121
	return (gpointer) TRUE;
122
}
123
124
static void
125
lookup_thread_free (LookupThread *thread)
126
{
127
	g_return_if_fail (thread != NULL);
128
129
	g_mutex_free (thread->lock);
130
	memset (thread, 0, sizeof (LookupThread));
131
	g_free (thread);
132
}
133
134
static LookupThread *
135
lookup_thread_new (guint32 ip4_addr, LookupCallback callback, gpointer user_data)
136
{
137
	LookupThread *thread;
138
139
	thread = g_malloc0 (sizeof (LookupThread));
140
	if (!thread)
141
		return NULL;
142
143
	thread->lock = g_mutex_new ();
144
	thread->callback = callback;
145
	thread->user_data = user_data;
146
	thread->ip4_addr = ip4_addr;
147
148
	thread->thread = g_thread_create (lookup_thread_worker, thread, FALSE, NULL);
149
	if (!thread->thread) {
150
		lookup_thread_free (thread);
151
		return NULL;
152
	}
153
154
	return thread;
155
}
156
157
static void
158
lookup_thread_die (LookupThread *thread)
159
{
160
	g_return_if_fail (thread != NULL);
161
162
	g_mutex_lock (thread->lock);
163
	thread->die = TRUE;
164
	g_mutex_unlock (thread->lock);
165
}
166
167
#define INVALID_TAG "invalid"
61
#define INVALID_TAG "invalid"
168
62
169
static const char *
63
static const char *
Lines 253-485 Link Here
253
	return best;
147
	return best;
254
}
148
}
255
149
256
#define FALLBACK_HOSTNAME "localhost.localdomain"
257
258
static gboolean
259
update_etc_hosts (const char *hostname)
260
{
261
	char *contents = NULL;
262
	char **lines = NULL, **line;
263
	GError *error = NULL;
264
	gboolean initial_comments = TRUE;
265
	gboolean added = FALSE;
266
	gsize contents_len = 0;
267
	GString *new_contents;
268
	gboolean success = FALSE;
269
270
	g_return_val_if_fail (hostname != NULL, FALSE);
271
272
	if (!g_file_get_contents (SYSCONFDIR "/hosts", &contents, &contents_len, &error)) {
273
		nm_warning ("%s: couldn't read " SYSCONFDIR "/hosts: (%d) %s",
274
		            __func__, error ? error->code : 0,
275
		            (error && error->message) ? error->message : "(unknown)");
276
		if (error)
277
			g_error_free (error);
278
	} else {
279
		lines = g_strsplit_set (contents, "\n\r", 0);
280
		g_free (contents);
281
	}
282
283
	new_contents = g_string_sized_new (contents_len ? contents_len + 100 : 200);
284
	if (!new_contents) {
285
		nm_warning ("%s: not enough memory to update " SYSCONFDIR "/hosts", __func__);
286
		return FALSE;
287
	}
288
289
	/* Replace any 127.0.0.1 entry that is at the beginning of the file or right
290
	 * after initial comments.  If there is no 127.0.0.1 entry at the beginning
291
	 * or after initial comments, add one there and ignore any other 127.0.0.1
292
	 * entries.
293
	 */
294
	for (line = lines; lines && *line; line++) {
295
		gboolean add_line = TRUE;
296
297
		/* This is the first line after the initial comments */
298
		if (initial_comments && (*line[0] != '#')) {
299
			initial_comments = FALSE;
300
			g_string_append_printf (new_contents, "127.0.0.1\t%s", hostname);
301
			if (strcmp (hostname, FALLBACK_HOSTNAME))
302
				g_string_append_printf (new_contents, "\t" FALLBACK_HOSTNAME);
303
			g_string_append (new_contents, "\tlocalhost\n");
304
			added = TRUE;
305
306
			/* Don't add the entry if it's supposed to be the actual localhost reverse mapping */
307
			if (!strncmp (*line, "127.0.0.1", strlen ("127.0.0.1")) && strstr (*line, "localhost"))
308
				add_line = FALSE;
309
		}
310
311
		if (add_line) {
312
			g_string_append (new_contents, *line);
313
			/* Only append the new line if this isn't the last line in the file */
314
			if (*(line+1))
315
				g_string_append_c (new_contents, '\n');
316
		}
317
	}
318
319
	/* Hmm, /etc/hosts was empty for some reason */
320
	if (!added) {
321
		g_string_append (new_contents, "# Do not remove the following line, or various programs");
322
		g_string_append (new_contents, "# that require network functionality will fail.");
323
		g_string_append (new_contents, "127.0.0.1\t" FALLBACK_HOSTNAME "\tlocalhost");
324
	}
325
326
	error = NULL;
327
	if (!g_file_set_contents (SYSCONFDIR "/hosts", new_contents->str, -1, &error)) {
328
		nm_warning ("%s: couldn't update " SYSCONFDIR "/hosts: (%d) %s",
329
		            __func__, error ? error->code : 0,
330
		            (error && error->message) ? error->message : "(unknown)");
331
		if (error)
332
			g_error_free (error);
333
	} else
334
		success = TRUE;
335
336
	g_string_free (new_contents, TRUE);
337
	return success;
338
}
339
340
static void
341
set_system_hostname (const char *new_hostname, const char *msg)
342
{
343
	char old_hostname[HOST_NAME_MAX + 1];
344
	int ret = 0;
345
	const char *name = new_hostname ? new_hostname : FALLBACK_HOSTNAME;
346
347
	old_hostname[HOST_NAME_MAX] = '\0';
348
	errno = 0;
349
	ret = gethostname (old_hostname, HOST_NAME_MAX);
350
	if (ret != 0) {
351
		nm_warning ("%s: couldn't get the system hostname: (%d) %s",
352
		            __func__, errno, strerror (errno));
353
	} else {
354
		/* Do nothing if the hostname isn't actually changing */
355
		if (   (new_hostname && !strcmp (old_hostname, new_hostname))
356
		    || (!new_hostname && !strcmp (old_hostname, FALLBACK_HOSTNAME)))
357
			return;
358
	}
359
360
	nm_info ("Setting system hostname to '%s' (%s)", name, msg);
361
362
	ret = sethostname (name, strlen (name));
363
	if (ret == 0) {
364
		if (!update_etc_hosts (name)) {
365
			/* error updating /etc/hosts; fallback to localhost.localdomain */
366
			nm_info ("Setting system hostname to '" FALLBACK_HOSTNAME "' (error updating /etc/hosts)");
367
			ret = sethostname (FALLBACK_HOSTNAME, strlen (FALLBACK_HOSTNAME));
368
			if (ret != 0) {
369
				nm_warning ("%s: couldn't set the fallback system hostname (%s): (%d) %s",
370
				            __func__, FALLBACK_HOSTNAME, errno, strerror (errno));
371
			}
372
		}
373
		nm_utils_call_dispatcher ("hostname", NULL, NULL, NULL);
374
	} else {
375
		nm_warning ("%s: couldn't set the system hostname to '%s': (%d) %s",
376
		            __func__, name, errno, strerror (errno));
377
	}
378
}
379
380
static void
381
lookup_callback (LookupThread *thread, gpointer user_data)
382
{
383
	NMPolicy *policy = (NMPolicy *) user_data;
384
385
	/* If the thread was told to die or it's not the current in-progress
386
	 * hostname lookup, nothing to do.
387
	 */
388
	if (thread->die || (thread != policy->lookup))
389
		goto done;
390
391
	policy->lookup = NULL;
392
	if (!strlen (thread->hostname)) {
393
		char *msg;
394
395
		/* No valid IP4 config (!!); fall back to localhost.localdomain */
396
		msg = g_strdup_printf ("address lookup failed: %d", thread->ret);
397
		set_system_hostname (NULL, msg);
398
		g_free (msg);
399
	} else
400
		set_system_hostname (thread->hostname, "from address lookup");
401
402
done:
403
	lookup_thread_free (thread);
404
}
405
406
static void
407
update_system_hostname (NMPolicy *policy, NMDevice *best)
408
{
409
	char *configured_hostname = NULL;
410
	NMActRequest *best_req = NULL;
411
	NMDHCP4Config *dhcp4_config;
412
	NMIP4Config *ip4_config;
413
	NMIP4Address *addr;
414
415
	g_return_if_fail (policy != NULL);
416
417
	if (policy->lookup) {
418
		lookup_thread_die (policy->lookup);
419
		policy->lookup = NULL;
420
	}
421
422
	/* A configured hostname (via the system-settings service) overrides
423
	 * all automatic hostname determination.  If there is no configured hostname,
424
	 * the best device's automatically determined hostname (from DHCP, VPN, PPP,
425
	 * etc) is used.  If there is no automatically determined hostname, reverse
426
	 * DNS lookup using the best device's IP address is started to determined the
427
	 * the hostname.
428
	 */
429
430
	/* Try a configured hostname first */
431
	g_object_get (G_OBJECT (policy->manager), NM_MANAGER_HOSTNAME, &configured_hostname, NULL);
432
	if (configured_hostname) {
433
		set_system_hostname (configured_hostname, "from system configuration");
434
		g_free (configured_hostname);
435
		return;
436
	}
437
438
	/* Try automatically determined hostname from the best device's IP config */
439
	if (!best)
440
		best = get_best_device (policy->manager, &best_req);
441
442
	if (!best) {
443
		/* No best device; fall back to localhost.localdomain */
444
		set_system_hostname (NULL, "no default device");
445
		return;
446
	}
447
448
	/* Grab a hostname out of the device's DHCP4 config */
449
	dhcp4_config = nm_device_get_dhcp4_config (best);
450
	if (dhcp4_config) {
451
		const char *dhcp4_hostname;
452
453
		dhcp4_hostname = nm_dhcp4_config_get_option (dhcp4_config, "host_name");
454
		if (dhcp4_hostname && strlen (dhcp4_hostname)) {
455
			set_system_hostname (dhcp4_hostname, "from DHCP");
456
			return;
457
		}
458
	}
459
460
	/* No configured hostname, no automatically determined hostname either. Start
461
	 * reverse DNS of the current IP address to try and find it.
462
	 */
463
	ip4_config = nm_device_get_ip4_config (best);
464
	if (   !ip4_config
465
	    || (nm_ip4_config_get_num_nameservers (ip4_config) == 0)
466
	    || (nm_ip4_config_get_num_addresses (ip4_config) == 0)) {
467
		/* No valid IP4 config (!!); fall back to localhost.localdomain */
468
		set_system_hostname (NULL, "no IPv4 config");
469
		return;
470
	}
471
472
	addr = nm_ip4_config_get_address (ip4_config, 0);
473
	g_assert (addr); /* checked for > 1 address above */
474
475
	/* Start the hostname lookup thread */
476
	policy->lookup = lookup_thread_new (nm_ip4_address_get_address (addr), lookup_callback, policy);
477
	if (!policy->lookup) {
478
		/* Fall back to 'localhost.localdomain' */
479
		set_system_hostname (NULL, "error starting hostname thread");
480
	}
481
}
482
483
static void
150
static void
484
update_routing_and_dns (NMPolicy *policy, gboolean force_update)
151
update_routing_and_dns (NMPolicy *policy, gboolean force_update)
485
{
152
{
Lines 597-605 Link Here
597
		nm_info ("Policy set (%s) as default for routing and DNS.", ip_iface);
264
		nm_info ("Policy set (%s) as default for routing and DNS.", ip_iface);
598
265
599
out:
266
out:
600
	/* Update the system hostname */
601
	update_system_hostname (policy, best);
602
603
	policy->default_device = best;	
267
	policy->default_device = best;	
604
}
268
}
605
269
Lines 707-718 Link Here
707
}
371
}
708
372
709
static void
373
static void
710
hostname_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data)
711
{
712
	update_system_hostname ((NMPolicy *) user_data, NULL);
713
}
714
715
static void
716
schedule_activate_check (NMPolicy *policy, NMDevice *device)
374
schedule_activate_check (NMPolicy *policy, NMDevice *device)
717
{
375
{
718
	ActivateData *data;
376
	ActivateData *data;
Lines 991-1000 Link Here
991
	                       G_CALLBACK (global_state_changed), policy);
649
	                       G_CALLBACK (global_state_changed), policy);
992
	policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id);
650
	policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id);
993
651
994
	id = g_signal_connect (manager, "notify::hostname",
995
	                       G_CALLBACK (hostname_changed), policy);
996
	policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id);
997
998
	id = g_signal_connect (manager, "device-added",
652
	id = g_signal_connect (manager, "device-added",
999
	                       G_CALLBACK (device_added), policy);
653
	                       G_CALLBACK (device_added), policy);
1000
	policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id);
654
	policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id);
Lines 1033-1046 Link Here
1033
687
1034
	g_return_if_fail (policy != NULL);
688
	g_return_if_fail (policy != NULL);
1035
689
1036
	/* Tell any existing hostname lookup thread to die, it'll get cleaned up
1037
	 * by the lookup thread callback.
1038
	  */
1039
	if (policy->lookup) {
1040
		lookup_thread_die (policy->lookup);
1041
		policy->lookup = NULL;
1042
	}
1043
1044
	for (iter = policy->pending_activation_checks; iter; iter = g_slist_next (iter)) {
690
	for (iter = policy->pending_activation_checks; iter; iter = g_slist_next (iter)) {
1045
		ActivateData *data = (ActivateData *) iter->data;
691
		ActivateData *data = (ActivateData *) iter->data;
1046
692

Return to bug 259634