diff --git a/SOURCES/authconfig-6.2.8-altfiles.patch b/SOURCES/authconfig-6.2.8-altfiles.patch new file mode 100644 index 0000000..97c39d3 --- /dev/null +++ b/SOURCES/authconfig-6.2.8-altfiles.patch @@ -0,0 +1,31 @@ +diff -up authconfig-6.2.8/authinfo.py.altfiles authconfig-6.2.8/authinfo.py +--- authconfig-6.2.8/authinfo.py.altfiles 2014-09-29 15:27:57.000000000 +0200 ++++ authconfig-6.2.8/authinfo.py 2014-09-29 15:31:41.371715194 +0200 +@@ -1333,6 +1333,9 @@ class AuthInfo: + self.preferDNSinHosts = None + self.enableSSSD = None + self.enableIPAv2 = None ++ # This one we don't have a config entry, we just ++ # preserve the entry if we see it. ++ self.enableAltfiles = None + + # Authentication setup. + self.enableAFS = None +@@ -2042,7 +2045,7 @@ class AuthInfo: + if nssconfig: + nssmap = (('Compat', 'compat'), ('DB', 'db'), + ('Directories', 'directories'), ('Hesiod', 'hesiod'), +- ('LDAP', 'ldap'), ('NIS', 'nis'), ++ ('LDAP', 'ldap'), ('NIS', 'nis'), ('Altfiles', 'altfiles'), + ('NIS3', 'nisplus'), ('Winbind', 'winbind')) + for attr, nssentry in nssmap: + if checkNSS(nssconfig, nssentry): +@@ -3583,6 +3586,8 @@ class AuthInfo: + if self.enableDB: + normal += " db" + normal += " files" ++ if self.enableAltfiles: ++ normal += " altfiles" + services = normal + if self.enableDirectories: + normal += " directories" diff --git a/SOURCES/authconfig-6.2.8-ipav2join.patch b/SOURCES/authconfig-6.2.8-ipav2join.patch new file mode 100644 index 0000000..b2965ad --- /dev/null +++ b/SOURCES/authconfig-6.2.8-ipav2join.patch @@ -0,0 +1,203 @@ +diff -up authconfig-6.2.8/authconfig-gtk.py.ipav2join authconfig-6.2.8/authconfig-gtk.py +--- authconfig-6.2.8/authconfig-gtk.py.ipav2join 2014-09-29 15:18:58.252487444 +0200 ++++ authconfig-6.2.8/authconfig-gtk.py 2014-09-29 15:19:15.077867285 +0200 +@@ -2,12 +2,13 @@ + # -*- coding: UTF-8 -*- + # + # Authconfig - client authentication configuration program +-# Copyright (c) 1999-2008 Red Hat, Inc. ++# Copyright (c) 1999-2014 Red Hat, Inc. + # + # Authors: Preston Brown + # Nalin Dahyabhai + # Matt Wilson + # Tomas Mraz ++# Jan Lieskovsky + # + # This is free software; you can redistribute it and/or modify it + # under the terms of the GNU General Public License as published by +@@ -236,6 +237,7 @@ class Authconfig: + self.oldrealm = "" + self.oldkdc = "" + self.oldadminserver = "" ++ self.messageParent = None + + def destroy_widget(self, button, widget): + widget.destroy() +@@ -272,7 +274,9 @@ class Authconfig: + response = self.run_on_button(None, "joinwbdomain", + "winbindjoin_map", parent) + if (response == gtk.RESPONSE_OK): +- self.info.joinDomain(True) ++ self.messageParent = parent ++ self.info.joinDomain(False) ++ self.messageParent = None + self.info.joinUser = None + self.info.joinPassword = None + +@@ -287,7 +291,9 @@ class Authconfig: + response = self.run_on_button(None, "joinipadomain", + "ipav2join_map", parent) + if (response == gtk.RESPONSE_OK): +- self.info.joinIPADomain(True) ++ self.messageParent = parent ++ self.info.joinIPADomain(False) ++ self.messageParent = None + + def info_apply(self, map, xml): + for entry in map.keys(): +@@ -796,10 +802,12 @@ class Authconfig: + response = self.run_on_button(None, "ldapcacertdownload", + "ldapcacert_map", parent) + if (response == gtk.RESPONSE_OK): ++ self.messageParent = parent + self.info.downloadLDAPCACert() ++ self.messageParent = None + + def message_callback(self, text): +- msg = gtk.MessageDialog(None, 0, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, text) ++ msg = gtk.MessageDialog(self.messageParent, 0, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, text) + msg.set_title(_("Authentication Configuration")) + msg.run() + msg.destroy() +diff -up authconfig-6.2.8/authinfo.py.ipav2join authconfig-6.2.8/authinfo.py +--- authconfig-6.2.8/authinfo.py.ipav2join 2014-09-29 15:14:59.000000000 +0200 ++++ authconfig-6.2.8/authinfo.py 2014-09-29 15:15:55.776367966 +0200 +@@ -1,7 +1,7 @@ + # -*- coding: UTF-8 -*- + # + # Authconfig - client authentication configuration program +-# Copyright (c) 1999-2011 Red Hat, Inc. ++# Copyright (c) 1999-2014 Red Hat, Inc. + # + # Authors: Preston Brown + # Nalin Dahyabhai +@@ -10,6 +10,7 @@ + # Ray Strode + # Paolo Bonzini + # Miloslav Trmac ++# Jan Lieskovsky + # + # This is free software; you can redistribute it and/or modify it + # under the terms of the GNU General Public License as published by +@@ -879,9 +880,17 @@ def feedFork(command, echo, query, respo + return 255 + if not pid: + # child +- status = os.system(command) ++ if query: ++ child = Popen([command], shell=True) ++ else: ++ child = Popen([command], stdin=PIPE, shell=True) ++ child.communicate(input=(response or '')+'\n') ++ ++ # wait for the child to terminate & set the returncode ++ child.wait() ++ status = child.returncode + os._exit(status) +- output = "" ++ (output, error) = ("","") + try: + i = fcntl.fcntl(master, fcntl.F_GETFL) + fcntl.fcntl(master, fcntl.F_SETFL, i & ~os.O_NONBLOCK) +@@ -918,13 +927,24 @@ def feedFork(command, echo, query, respo + if c: + try: + output += c ++ error += c + if echo: + sys.stderr.write(c) +- if query in output: +- os.write(master, response) ++ if query and query in output: ++ # Search for password prompt start ++ index = error.rfind("\r\n") ++ os.write(master, response or '') + os.write(master, "\r\n") ++ if index != -1: ++ # Drop password prompt substring from error ++ error = "\n" + error[:index] ++ else: ++ # Drop whole error content, password prompt ++ # was the first line ++ error = "" + output = "" +- sys.stderr.write("<...>\n") ++ if echo: ++ sys.stderr.write("<...>\n") + except OSError, (err, text): + sys.stderr.write("write: " + text + "\n") + os.close(master) +@@ -941,7 +961,7 @@ def feedFork(command, echo, query, respo + (child, status) = os.waitpid(pid, 0) + except OSError, (err, text): + sys.stderr.write("waitpid: " + text + "\n") +- return status ++ return (status, error) + + def isEmptyDir(path): + try: +@@ -4227,17 +4247,26 @@ class AuthInfo: + # Not needed -- "joining" is meaningless for other + # models. + return +- cmd = "/usr/bin/net join %s%s %s%s -U %s" % ( ++ cmd = PATH_WINBIND_NET + " join %s%s %s%s -U %s" % ( + domain and "-w " or "", domain, + server and "-S " or "", server, + self.joinUser) + + if echo: + sys.stderr.write("[%s]\n" % cmd) +- if self.joinPassword: +- status = feedFork(cmd, echo, "sword:", self.joinPassword) ++ child = Popen([cmd], shell=True) ++ child.communicate() ++ status = child.returncode ++ else: ++ status, error = feedFork(cmd, echo, "sword:", self.joinPassword) ++ if echo: ++ if status != 0: ++ self.messageCB(_("Winbind domain join was not successful.")) + else: +- status = os.system(cmd) ++ if status != 0: ++ errmsg = _("Winbind domain join was not successful. The net join command failed with the following error:") ++ errmsg += "\n" + error ++ self.messageCB(errmsg) + return status == 0 + + def joinIPADomain(self, echo): +@@ -4258,18 +4287,26 @@ class AuthInfo: + realm and "--realm=" or "", realm, + principal and "--principal=" or "", principal, + nontp, +- password and "-W" or "") +- ++ not echo and "--unattended" or "-W") ++ + if echo: + sys.stderr.write("[%s]\n" % cmd) +- if self.joinPassword: +- status = feedFork(cmd, echo, "sword:", self.joinPassword) ++ child = Popen([cmd], shell=True) ++ child.communicate() ++ status = child.returncode + else: +- status = os.system(cmd) ++ status, error = feedFork(cmd, echo, '', password) ++ + if status == 0: + self.ipaDomainJoined = True ++ if echo: ++ if status != 0: ++ self.messageCB(_("IPAv2 domain join was not successful.")) + else: +- self.messageCB(_("IPAv2 domain join was not succesful. The ipa-client-install command failed.")) ++ if status != 0: ++ errmsg = _("IPAv2 domain join was not successful. The ipa-client-install command failed with the following error:") ++ errmsg += "\n" + error ++ self.messageCB(errmsg) + return status == 0 + + def uninstallIPA(self): diff --git a/SOURCES/authconfig-6.2.8-ldapbase.patch b/SOURCES/authconfig-6.2.8-ldapbase.patch new file mode 100644 index 0000000..43bad99 --- /dev/null +++ b/SOURCES/authconfig-6.2.8-ldapbase.patch @@ -0,0 +1,26 @@ +diff -up authconfig-6.2.8/authinfo.py.ldapbase authconfig-6.2.8/authinfo.py +--- authconfig-6.2.8/authinfo.py.ldapbase 2014-09-29 15:15:55.000000000 +0200 ++++ authconfig-6.2.8/authinfo.py 2014-09-29 15:27:57.504661297 +0200 +@@ -188,6 +188,13 @@ def checkDN(value): + return False + return True + ++def matchBaseLine(line, key): ++ value = matchKey(line, key) ++ if value: ++ return checkDN(value) ++ else: ++ return False ++ + # Check for a string in an nss configuration line. + def checkNSS(configuration, candidate): + lst = configuration.split(":",1) +@@ -2636,7 +2643,7 @@ class AuthInfo: + elif matchLine(ls, host): + if self.ldapServer: + output += "#" + line +- elif matchLine(ls, base): ++ elif matchBaseLine(ls, base): + # If it's a 'base' line, insert ours instead. + if not wrotebasedn and self.ldapBaseDN: + output += base + " " diff --git a/SOURCES/authconfig-6.2.8-multiple-ldap-uris.patch b/SOURCES/authconfig-6.2.8-multiple-ldap-uris.patch new file mode 100644 index 0000000..de3665c --- /dev/null +++ b/SOURCES/authconfig-6.2.8-multiple-ldap-uris.patch @@ -0,0 +1,104 @@ +diff -up authconfig-6.2.8/authconfig-gtk.py.ldap-uris authconfig-6.2.8/authconfig-gtk.py +--- authconfig-6.2.8/authconfig-gtk.py.ldap-uris 2014-09-29 15:41:20.000000000 +0200 ++++ authconfig-6.2.8/authconfig-gtk.py 2014-09-29 15:49:09.277372121 +0200 +@@ -526,6 +526,7 @@ class Authconfig: + if not ldapserver: + return True + uritovalidate = ldapserver.get_text() ++ uritovalidate = self.info.ldapHostsToURIs(uritovalidate, False) + return self.info.validateLDAPURI(uritovalidate) + + def enable_cacert_download(self, active, xml): +diff -up authconfig-6.2.8/authinfo.py.ldap-uris authconfig-6.2.8/authinfo.py +--- authconfig-6.2.8/authinfo.py.ldap-uris 2014-09-29 15:44:28.000000000 +0200 ++++ authconfig-6.2.8/authinfo.py 2014-09-29 15:49:48.156249829 +0200 +@@ -1588,20 +1588,24 @@ class AuthInfo: + + def validateLDAPURI(self, s): + """ +- Check LDAP URI provided in the form of literal IPv6 address +- for correctness. +- +- Return False if IPv6 valid is invalid or urlparse failed to +- obtain integer port value, True otherwise. ++ Check whether LDAP URI is valid. + """ +- try: +- p = urlparse.urlparse(s).port +- return True +- except ValueError: +- return False ++ if ',' in s: ++ uris = s.split(',') ++ else: ++ uris = s.split() ++ for uri in uris: ++ try: ++ p = urlparse.urlparse(uri).port ++ except (ValueError, socket.error): ++ return False ++ return True + +- def ldapHostsToURIs(self, s): +- l = s.split(",") ++ def ldapHostsToURIs(self, s, validate): ++ if ',' in s: ++ l = s.split(',') ++ else: ++ l = s.split() + ret = "" + for item in l: + if item: +@@ -1611,9 +1615,8 @@ class AuthInfo: + ret += item + else: + ret += "ldap://" + item + "/" +- if not self.validateLDAPURI(ret): ++ if validate and not self.validateLDAPURI(ret): + self.messageCB(_("Invalid LDAP URI.")) +- return "" + return ret + + # Read LDAP setup from /etc/ldap.conf. +@@ -1669,7 +1672,7 @@ class AuthInfo: + # We'll pull MD5/DES crypt ("pam_password") from the config + # file, or from the pam_unix PAM config lines. + +- self.ldapServer = self.ldapHostsToURIs(cleanList(self.ldapServer)) ++ self.ldapServer = self.ldapHostsToURIs(cleanList(self.ldapServer), False) + f.close() + return True + +@@ -2456,12 +2459,12 @@ class AuthInfo: + # suggestions we "know". The second case is when the user has just made a + # change to one field and we need to update another field to somehow + # compensate for the change. +- def update(self): ++ def update(self, validate=False): + self.smbServers = cleanList(self.smbServers) + self.ipav2Server = cleanList(self.ipav2Server) + self.kerberosKDC = cleanList(self.kerberosKDC) + self.kerberosAdminServer = cleanList(self.kerberosAdminServer) +- self.ldapServer = self.ldapHostsToURIs(self.ldapServer) ++ self.ldapServer = self.ldapHostsToURIs(self.ldapServer, validate) + if self.smbSecurity == "ads": + # As of this writing, an ADS implementation always + # upper-cases the realm name, even if only internally, +@@ -4024,7 +4027,7 @@ class AuthInfo: + self.ipaUninstall = True + + def write(self): +- self.update() ++ self.update(True) + self.prewriteUpdate() + self.setupBackup(PATH_CONFIG_BACKUPS + "/last") + try: +@@ -4064,7 +4067,7 @@ class AuthInfo: + + def writeChanged(self, ref): + self.checkPAMLinked() +- self.update() ++ self.update(True) + self.prewriteUpdate() + self.setupBackup(PATH_CONFIG_BACKUPS + "/last") + ret = True diff --git a/SOURCES/authconfig-6.2.8-services.patch b/SOURCES/authconfig-6.2.8-services.patch new file mode 100644 index 0000000..0182d51 --- /dev/null +++ b/SOURCES/authconfig-6.2.8-services.patch @@ -0,0 +1,113 @@ +diff -up authconfig-6.2.8/authconfig-gtk.py.services authconfig-6.2.8/authconfig-gtk.py +--- authconfig-6.2.8/authconfig-gtk.py.services 2014-09-29 15:37:19.000000000 +0200 ++++ authconfig-6.2.8/authconfig-gtk.py 2014-09-29 15:41:20.478788789 +0200 +@@ -257,7 +257,7 @@ class Authconfig: + self.info = backup + # Save. + if (response == 1): +- self.apply() ++ self.apply(nostart=True) + backup = self.info + return backup + +@@ -266,7 +266,10 @@ class Authconfig: + if not backup: + return + self.winbindjoin_launch(button, map, xml, parent) +- self.info = backup ++ if self.info != backup: ++ self.info = backup ++ else: ++ self.apply() + + def winbindjoin_launch(self, button, map, xml, parent): + if not self.info.joinUser: +@@ -285,7 +288,10 @@ class Authconfig: + if not backup: + return + self.ipav2join_launch(button, map, xml, parent) +- self.info = backup ++ if self.info != backup: ++ self.info = backup ++ else: ++ self.apply() + + def ipav2join_launch(self, button, map, xml, parent): + response = self.run_on_button(None, "joinipadomain", +@@ -772,7 +778,7 @@ class Authconfig: + return dialog + + # Save changes. +- def apply(self): ++ def apply(self, nostart = False): + self.update_type(self.id_map, self.currid) + self.update_type(self.auth_map, self.currauth) + self.apply_idsettings() +@@ -788,7 +794,7 @@ class Authconfig: + else: + self.info.writeChanged(self.pristineinfo) + +- self.info.post(False) ++ self.info.post(nostart) + if "--firstboot" in sys.argv: + for service in firstbootservices: + if authinfo.Service.isEnabled(service): +diff -up authconfig-6.2.8/authinfo.py.services authconfig-6.2.8/authinfo.py +--- authconfig-6.2.8/authinfo.py.services 2014-09-29 15:43:38.000000000 +0200 ++++ authconfig-6.2.8/authinfo.py 2014-09-29 15:44:28.629036362 +0200 +@@ -4395,15 +4395,15 @@ class AuthInfo: + "winbind", nostart) + + def toggleSSSDService(self, nostart): +- + explicitenable = ((self.enableSSSD and self.enableSSSDAuth) or + (self.enableSSSD and os.path.exists(PATH_SSSD_CONFIG)) or + (self.enableSSSDAuth and os.path.exists(PATH_SSSD_CONFIG))) +- toggleSplatbindService(self.implicitSSSD or self.implicitSSSDAuth or +- self.enableIPAv2 or explicitenable, ++ enable = (self.implicitSSSD or self.implicitSSSDAuth or ++ self.enableIPAv2 or explicitenable) ++ toggleSplatbindService(enable, + PATH_SSSD, +- "sssd", nostart or not (self.implicitSSSD or self.implicitSSSDAuth +- or self.enableIPAv2)) ++ "sssd", nostart or (enable and not (self.implicitSSSD or ++ self.implicitSSSDAuth or self.enableIPAv2))) + + def toggleOddjobService(self, nostart): + if self.enableMkHomeDir and os.access("%s/pam_%s.so" +diff -up authconfig-6.2.8/man/en/authconfig.8.services authconfig-6.2.8/man/en/authconfig.8 +--- authconfig-6.2.8/man/en/authconfig.8.services 2013-11-01 16:08:01.000000000 +0100 ++++ authconfig-6.2.8/man/en/authconfig.8 2014-09-29 15:40:31.872691485 +0200 +@@ -35,7 +35,7 @@ be restored by the \fB--restorelastbacku + + If \fB--nostart\fR is specified (which is what the install program does), + ypbind or other daemons will not be started or stopped immediately following +-program execution, but only enabled to start or stop at boot time. ++program execution, but only enabled to start or stop at boot time. + + The \fB--enablenis\fP, \fB--enableldap\fP, \fB--enablewinbind\fP, + and \fB--enablehesiod\fP options +@@ -94,6 +94,22 @@ The \fB/usr/bin/authconfig\fR uses the \ + system user before it starts up. If you want to run it directly without the + authentication as the system user, run the \fB/usr/sbin/authconfig\fR command. + ++The SSSD service is enabled and possibly started by authconfig when at least two of ++the following three conditions are met: ++.br ++1) /etc/sssd/sssd.conf file exists (or is configured via the implicit SSSD support) ++.br ++2) SSSD authentication is enabled (pam_sss.so is used in PAM configuration) ++.br ++3) SSSD is enabled for user identity (nsswitch.conf contains sss) ++ ++When \fB--update\fR action is used the enablement or disablement and possible restart ++of services happens only in case the changed configuration options affect the ++service to be restarted. This means that if for example the ypbind service is ++enabled with \fBauthconfig --update --nostart --enablenis\fR but not started ++and you run the same command without the \fB--nostart\fR later the ypbind ++service will not be started because no configuration change affecting ypbind ++happened. + .PD + .SH "RETURN CODES" + \fBauthconfig\fR returns 0 on success, 1 on backup operation errors, diff --git a/SOURCES/authconfig-6.2.8-winbind-client.patch b/SOURCES/authconfig-6.2.8-winbind-client.patch new file mode 100644 index 0000000..e1150d7 --- /dev/null +++ b/SOURCES/authconfig-6.2.8-winbind-client.patch @@ -0,0 +1,12 @@ +diff -up authconfig-6.2.8/authconfig-gtk.py.winbind-client authconfig-6.2.8/authconfig-gtk.py +--- authconfig-6.2.8/authconfig-gtk.py.winbind-client 2014-09-29 15:19:15.000000000 +0200 ++++ authconfig-6.2.8/authconfig-gtk.py 2014-09-29 15:37:19.586350537 +0200 +@@ -130,7 +130,7 @@ class Authconfig: + "nisoptions", "nis_map", authinfo.PATH_LIBNSS_NIS, "ypbind"), + "Winbind": + (_("Winbind"), ("WinbindAuth",), +- "winbindoptions", "winbind_map", authinfo.PATH_WINBIND, "samba-winbind-clients"), ++ "winbindoptions", "winbind_map", authinfo.PATH_WINBIND, "samba-winbind"), + "IPAv2": + (_("IPAv2"), ("IPAv2Auth",), + "ipav2options", "ipav2_map", authinfo.PATH_IPA_CLIENT_INSTALL, "freeipa-client") diff --git a/SPECS/authconfig.spec b/SPECS/authconfig.spec index 65b10cb..9431ed0 100644 --- a/SPECS/authconfig.spec +++ b/SPECS/authconfig.spec @@ -1,7 +1,7 @@ Summary: Command line tool for setting up authentication from network services Name: authconfig Version: 6.2.8 -Release: 8%{?dist} +Release: 9%{?dist} License: GPLv2+ ExclusiveOS: Linux Group: System Environment/Base @@ -16,6 +16,12 @@ Patch6: authconfig-6.2.8-notraceback.patch Patch7: authconfig-6.2.8-restorecon.patch Patch8: authconfig-6.2.8-sssd-enable.patch Patch9: authconfig-6.2.8-translation-updates-2.patch +Patch10: authconfig-6.2.8-ipav2join.patch +Patch11: authconfig-6.2.8-ldapbase.patch +Patch12: authconfig-6.2.8-altfiles.patch +Patch13: authconfig-6.2.8-winbind-client.patch +Patch14: authconfig-6.2.8-services.patch +Patch15: authconfig-6.2.8-multiple-ldap-uris.patch Requires: newt-python, pam >= 0.99.10.0, python, libpwquality > 0.9 Conflicts: pam_krb5 < 1.49, samba-common < 3.0, samba-client < 3.0 Conflicts: nss_ldap < 254, sssd < 0.99.1 @@ -23,6 +29,7 @@ Conflicts: freeipa-client < 2.2.0, ipa-client < 2.2.0 BuildRequires: glib2-devel, python >= 2.6, python-devel BuildRequires: desktop-file-utils, intltool, gettext, perl-XML-Parser Requires: /usr/bin/openssl +Requires: policycoreutils %description Authconfig is a command line utility which can configure a workstation @@ -53,6 +60,12 @@ authentication schemes. %patch7 -p1 -b .restorecon %patch8 -p1 -b .sssd-enable %patch9 -p1 -b .translations2 +%patch10 -p1 -b .ipav2join +%patch11 -p1 -b .ldapbase +%patch12 -p1 -b .altfiles +%patch13 -p1 -b .winbind-client +%patch14 -p1 -b .services +%patch15 -p1 -b .ldap-uris %build %configure @@ -135,6 +148,15 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : %{_datadir}/icons/hicolor/256x256/apps/system-config-authentication.* %changelog +* Mon Sep 29 2014 Tomáš Mráz - 6.2.8-9 +- do not overwrite special ldap base values +- display error message if winbind or IPA domain join fails +- fix invocation of IPA domain join from GUI +- keep altfiles in nsswitch.conf if present (#1134084) +- the winbind client is now in samba-winbind package (#1084997) +- correct handling of SSSD enablement during IPA domain joins +- do not bail out if multiple LDAP URIs are specified (#1142830) + * Tue Feb 11 2014 Tomáš Mráz - 6.2.8-8 - enable/start sssd only when config exists or enabled for both pam and nsswitch.conf