diff --git a/ChangeLog b/ChangeLog index 5fed9c539c..148036c83d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2008-09-05 Dan Williams + + Patch from Roy Marples and others + + * configure.in + src/named-manager/nm-named-manager.c + - Add support for resolvconf; use --with-resolvconf at configure time + to enable it + 2008-09-05 Dan Williams * libnm-util/crypto_nss.c diff --git a/configure.in b/configure.in index 9f7db7c91f..bd86fc229d 100644 --- a/configure.in +++ b/configure.in @@ -402,6 +402,39 @@ if test "$DHCP_CLIENT" != "dhclient" -a "$DHCP_CLIENT" != "dhcpcd"; then fi AC_SUBST(DHCP_CLIENT) +# resolvconf support +AC_ARG_WITH(crypto, AC_HELP_STRING([--with-crypto=nss | gnutls], [Cryptography library to use for certificate and key operations]),ac_crypto=$withval, ac_crypto=nss) +AC_ARG_WITH([resolvconf], + AS_HELP_STRING([--with-resolvconf=yes|no|path], [Enable resolvconf support]), + with_resolvconf="$withval",with_resolvconf=no) +# If a full path is given, use that and do not test if it works or not. +case "${with_resolvconf}" in + /*) + RESOLVCONF_PATH="${with_resolvconf}" + AC_MSG_NOTICE(setting resolvconf path to ${RESOLVCONF_PATH}) + ;; + no) AC_MSG_NOTICE(resolvconf support disabled) + ;; + *) + AC_MSG_CHECKING(for resolvconf) + for path in /sbin /usr/sbin /usr/pkg/sbin /usr/local/sbin; do + if test -x "${path}/resolvconf"; then + RESOLVCONF_PATH="${path}/resolvconf" + break + fi + done + if test -n "${RESOLVCONF_PATH}"; then + AC_MSG_RESULT($RESOLVCONF_PATH) + else + AC_MSG_RESULT(no) + fi + ;; +esac +AC_SUBST(RESOLVCONF_PATH) +if test -n "${RESOLVCONF_PATH}"; then + AC_DEFINE_UNQUOTED(RESOLVCONF_PATH, "$RESOLVCONF_PATH", [Define if you have a resolvconf implementation]) +fi + AC_ARG_ENABLE(more-warnings, AS_HELP_STRING([--enable-more-warnings], [Maximum compiler warnings]), set_more_warnings="$enableval",set_more_warnings=yes) AC_MSG_CHECKING(for more warnings, including -Werror) diff --git a/src/named-manager/nm-named-manager.c b/src/named-manager/nm-named-manager.c index 635a376f37..3c3d2dfdc5 100644 --- a/src/named-manager/nm-named-manager.c +++ b/src/named-manager/nm-named-manager.c @@ -23,6 +23,7 @@ #include "config.h" +#include #include #include #include @@ -38,6 +39,7 @@ #include "nm-ip4-config.h" #include "nm-utils.h" #include "NetworkManagerSystem.h" +#include "NetworkManagerUtils.h" #ifdef HAVE_SELINUX #include @@ -47,6 +49,8 @@ #define RESOLV_CONF "/etc/resolv.conf" #endif +#define ADDR_BUF_LEN 50 + G_DEFINE_TYPE(NMNamedManager, nm_named_manager, G_TYPE_OBJECT) #define NM_NAMED_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ @@ -115,6 +119,7 @@ merge_one_ip4_config (NMIP4Config *dst, NMIP4Config *src) } } + #if defined(TARGET_SUSE) /**********************************/ /* SUSE */ @@ -157,10 +162,9 @@ write_to_netconfig (gint fd, const char *key, const char *value) } static gboolean -update_resolv_conf (const char *iface, - const char *domain, - char **searches, +dispatch_netconfig (char **searches, char **nameservers, + const char *iface, GError **error) { gint fd; @@ -188,66 +192,52 @@ update_resolv_conf (const char *iface, return TRUE; } +#endif -#else -/**********************************/ -/* Generic */ static gboolean -update_resolv_conf (const char *iface, - const char *domain, - char **searches, - char **nameservers, - GError **error) +write_resolv_conf (FILE *f, const char *domain, + char **searches, + char **nameservers, + GError **error) { - const char *tmp_resolv_conf = RESOLV_CONF ".tmp"; char *domain_str = NULL; char *searches_str = NULL; char *nameservers_str = NULL; - FILE *f; + int i; + gboolean retval = FALSE; - if ((f = fopen (tmp_resolv_conf, "w")) == NULL) { - g_set_error (error, - NM_NAMED_MANAGER_ERROR, - NM_NAMED_MANAGER_ERROR_SYSTEM, - "Could not open " RESOLV_CONF ": %s\n", - g_strerror (errno)); - return FALSE; - } - - if (fprintf (f, "%s","# generated by NetworkManager, do not edit!\n\n") < 0) { + if (fprintf (f, "%s","# Generated by NetworkManager\n") < 0) { g_set_error (error, NM_NAMED_MANAGER_ERROR, NM_NAMED_MANAGER_ERROR_SYSTEM, "Could not write " RESOLV_CONF ": %s\n", g_strerror (errno)); - fclose (f); return FALSE; } if (domain) - domain_str = g_strconcat ("domain ", domain, "\n\n", NULL); + domain_str = g_strconcat ("domain ", domain, "\n", NULL); if (searches) { char *tmp_str; tmp_str = g_strjoinv (" ", searches); - searches_str = g_strconcat ("search ", tmp_str, "\n\n", NULL); + searches_str = g_strconcat ("search ", tmp_str, "\n", NULL); g_free (tmp_str); } if (nameservers) { GString *str; int num; - int i; str = g_string_new (""); num = g_strv_length (nameservers); for (i = 0; i < num; i++) { if (i == 3) { - g_string_append (str, "\n# "); - g_string_append (str, _("NOTE: the glibc resolver does not support more than 3 nameservers.")); + g_string_append (str, "# "); + g_string_append (str, _("NOTE: the libc resolver may not support more than 3 nameservers.")); g_string_append (str, "\n# "); g_string_append (str, _("The nameservers listed below may not be recognized.")); g_string_append_c (str, '\n'); @@ -261,27 +251,94 @@ update_resolv_conf (const char *iface, nameservers_str = g_string_free (str, FALSE); } - if (fprintf (f, "%s%s%s\n", - domain_str ? domain_str : "", + if (fprintf (f, "%s%s%s", + domain_str ? domain_str : "", searches_str ? searches_str : "", - nameservers_str ? nameservers_str : "") < 0) { - g_set_error (error, - NM_NAMED_MANAGER_ERROR, - NM_NAMED_MANAGER_ERROR_SYSTEM, - "Could not write to " RESOLV_CONF ": %s\n", - g_strerror (errno)); - } + nameservers_str ? nameservers_str : "") != -1) + retval = TRUE; g_free (domain_str); g_free (searches_str); g_free (nameservers_str); + return retval; +} + +#ifdef RESOLVCONF_PATH +static gboolean +dispatch_resolvconf (const char *domain, + char **searches, + char **nameservers, + const char *iface, + GError **error) +{ + char *cmd; + FILE *f; + gboolean retval = FALSE; + + if (! g_file_test (RESOLVCONF_PATH, G_FILE_TEST_IS_EXECUTABLE)) + return FALSE; + + if (domain || searches || nameservers) { + cmd = g_strconcat (RESOLVCONF_PATH, " -a ", "NetworkManager", NULL); + nm_info ("(%s): writing resolv.conf to %s", iface, RESOLVCONF_PATH); + if ((f = popen (cmd, "w")) == NULL) + g_set_error (error, + NM_NAMED_MANAGER_ERROR, + NM_NAMED_MANAGER_ERROR_SYSTEM, + "Could not write to %s: %s\n", + RESOLVCONF_PATH, + g_strerror (errno)); + else { + retval = write_resolv_conf (f, domain, searches, nameservers, error); + pclose (f); + } + } else { + cmd = g_strconcat (RESOLVCONF_PATH, " -d ", "NetworkManager", NULL); + nm_info ("(%s): removing resolv.conf from %s", iface, RESOLVCONF_PATH); + if (nm_spawn_process (cmd) == 0) + retval = TRUE; + } + + g_free (cmd); + + return retval; +} +#endif + +static gboolean +update_resolv_conf (const char *domain, + char **searches, + char **nameservers, + const char *iface, + GError **error) +{ + const char *tmp_resolv_conf = RESOLV_CONF ".tmp"; + char tmp_resolv_conf_realpath [PATH_MAX]; + FILE *f; + + if (!realpath(tmp_resolv_conf, tmp_resolv_conf_realpath)) + strcpy(tmp_resolv_conf_realpath, tmp_resolv_conf); + + if ((f = fopen (tmp_resolv_conf_realpath, "w")) == NULL) { + g_set_error (error, + NM_NAMED_MANAGER_ERROR, + NM_NAMED_MANAGER_ERROR_SYSTEM, + "Could not open %s: %s\n", + tmp_resolv_conf_realpath, + g_strerror (errno)); + return FALSE; + } + + write_resolv_conf (f, domain, searches, nameservers, error); + if (fclose (f) < 0) { if (*error == NULL) { g_set_error (error, NM_NAMED_MANAGER_ERROR, NM_NAMED_MANAGER_ERROR_SYSTEM, - "Could not close " RESOLV_CONF ": %s\n", + "Could not close %s: %s\n", + tmp_resolv_conf_realpath, g_strerror (errno)); } } @@ -298,9 +355,7 @@ update_resolv_conf (const char *iface, return *error ? FALSE : TRUE; } -#endif -#define ADDR_BUF_LEN 50 static gboolean rewrite_resolv_conf (NMNamedManager *mgr, const char *iface, GError **error) @@ -316,7 +371,7 @@ rewrite_resolv_conf (NMNamedManager *mgr, const char *iface, GError **error) int num_searches; int num_nameservers; int i; - gboolean success; + gboolean success = FALSE; g_return_val_if_fail (error != NULL, FALSE); g_return_val_if_fail (*error == NULL, FALSE); @@ -341,25 +396,9 @@ rewrite_resolv_conf (NMNamedManager *mgr, const char *iface, GError **error) merge_one_ip4_config (composite, config); } - /* ISC DHCP 3.1 provides support for the domain-search option. This is the - * correct way for a DHCP server to provide a domain search list. Wedging - * multiple domains into the domain-name option is a horrible hack. - * - * So, we handle it like this (as proposed by Andrew Pollock at - * http://bugs.debian.org/465158): - * - * - if the domain-search option is present in the data received via DHCP, - * use it in favour of the domain-name option for setting the search - * directive in /etc/resolv.conf - * - * - if the domain-name option is present in the data received via DHCP, use - * it to set the domain directive in /etc/resolv.conf - * (this is handled in compute_domain() below) - * - * - if only the domain-name option is present in the data received via DHCP - * (and domain-search is not), for backwards compatibility, set the search - * directive in /etc/resolv.conf to the specified domain names - */ + /* Some DHCP servers like to put multiple search paths into the domain + * option as the domain-search option wasn't around in the first RFC. + * We should try and support these old servers as best we can. */ num_domains = nm_ip4_config_get_num_domains (composite); num_searches = nm_ip4_config_get_num_searches (composite); @@ -369,18 +408,18 @@ rewrite_resolv_conf (NMNamedManager *mgr, const char *iface, GError **error) domain = nm_ip4_config_get_domain (composite, 0); /* Searches */ - if ((num_searches == 0) && (num_domains > 0)) { - array = g_ptr_array_sized_new (num_domains + 1); - for (i = 0; i < num_domains; i++) - g_ptr_array_add (array, g_strdup (nm_ip4_config_get_domain (composite, i))); - - g_ptr_array_add (array, NULL); - searches = (char **) g_ptr_array_free (array, FALSE); - } else if (num_searches > 0) { + if (num_searches > 0) { array = g_ptr_array_sized_new (num_searches + 1); for (i = 0; i < num_searches; i++) g_ptr_array_add (array, g_strdup (nm_ip4_config_get_search (composite, i))); + g_ptr_array_add (array, NULL); + searches = (char **) g_ptr_array_free (array, FALSE); + } else if (num_domains > 0) { + array = g_ptr_array_sized_new (num_domains + 1); + for (i = 0; i < num_domains; i++) + g_ptr_array_add (array, g_strdup (nm_ip4_config_get_domain (composite, i))); + g_ptr_array_add (array, NULL); searches = (char **) g_ptr_array_free (array, FALSE); } @@ -409,14 +448,24 @@ rewrite_resolv_conf (NMNamedManager *mgr, const char *iface, GError **error) nameservers = (char **) g_ptr_array_free (array, FALSE); } - success = update_resolv_conf (iface, domain, searches, nameservers, error); +#ifdef RESOLVCONF_PATH + success = dispatch_resolvconf (domain, searches, nameservers, iface, error); +#endif - g_strfreev (searches); - g_strfreev (nameservers); +#ifdef TARGET_SUSE + if (success == FALSE) + success = dispatch_netconfig (domain, searches, nameservers, iface, error); +#endif + + if (success == FALSE) + success = update_resolv_conf (domain, searches, nameservers, iface, error); if (success) nm_system_update_dns (); + g_strfreev (searches); + g_strfreev (nameservers); + return success; }