From 1a912a1fba6602c81bf874e619463b70ce10573b Mon Sep 17 00:00:00 2001 From: Alejandro Escanero Blanco Date: Wed, 7 Aug 2013 19:46:38 +0200 Subject: [PATCH] userPrincipalName changes for BUG 9486. It makes samba-tool behave more like ADUC Changes are: -> A option in samba-tool domain classicupgrade: --no-upn By default a userPrincipalName for each user with form username@realm is added to the account. This option don't add the userPrincipalName. -> Subcommand samba-tool user upn set|delete|show Manipulate userPrincipalName for each account Check upnsuffix before set userPrincipalName attribute -> A option in samba-tool user create --upn=UPN You can add a different userPrincipalName that username@realm to a Account when this is created. Check upnsuffix before set userPrincipalName attribute -> A option in samba-tool user create --no-upn exclusive with --upn default no You can choose don't create any userPrincipalName attribute -> Changes in smbtorture test in samba.tests.samba_tool.user: - Check if userPrincipalName is created in form username@REALM - Check samba-tool user upn set|delete with URL and without URL --- python/samba/netcmd/domain.py | 11 +- python/samba/netcmd/upn.py | 334 ++++++++++++++++++++++++++++++++++ python/samba/netcmd/user.py | 34 +++- python/samba/samdb.py | 82 ++++++++- python/samba/tests/samba_tool/user.py | 74 ++++++++ python/samba/upgrade.py | 44 ++++- 6 files changed, 557 insertions(+), 22 deletions(-) create mode 100644 python/samba/netcmd/upn.py diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py index 4ba305c..33864e1 100644 --- a/python/samba/netcmd/domain.py +++ b/python/samba/netcmd/domain.py @@ -1218,6 +1218,9 @@ class cmd_domain_classicupgrade(Command): help="Define if we should use the native fs capabilities or a tdb file for storing attributes likes ntacl, auto tries to make an inteligent guess based on the user rights and system capabilities", default="auto"), Option("--use-ntvfs", help="Use NTVFS for the fileserver (default = no)", action="store_true"), + Option("--no-upn", + help="Define if we shouldn't add attribute userPrincipalName \ + to the user accounts", action="store_true"), Option("--dns-backend", type="choice", metavar="NAMESERVER-BACKEND", choices=["SAMBA_INTERNAL", "BIND9_FLATFILE", "BIND9_DLZ", "NONE"], help="The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), " @@ -1231,7 +1234,7 @@ class cmd_domain_classicupgrade(Command): def run(self, smbconf=None, targetdir=None, dbdir=None, testparm=None, quiet=False, verbose=False, use_xattrs=None, sambaopts=None, versionopts=None, - dns_backend=None, use_ntvfs=False): + dns_backend=None, use_ntvfs=False, no_upn=False): if not os.path.exists(smbconf): raise CommandError("File %s does not exist" % smbconf) @@ -1314,8 +1317,10 @@ class cmd_domain_classicupgrade(Command): samba3 = Samba3(smbconf, s3conf) logger.info("Provisioning") - upgrade_from_samba3(samba3, logger, targetdir, session_info=system_session(), - useeadb=eadb, dns_backend=dns_backend, use_ntvfs=use_ntvfs) + upgrade_from_samba3(samba3, logger, targetdir, + session_info=system_session(), + useeadb=eadb, dns_backend=dns_backend, + use_ntvfs=use_ntvfs, no_upn=no_upn) class cmd_domain_samba3upgrade(cmd_domain_classicupgrade): diff --git a/python/samba/netcmd/upn.py b/python/samba/netcmd/upn.py new file mode 100644 index 0000000..bfe1743 --- /dev/null +++ b/python/samba/netcmd/upn.py @@ -0,0 +1,334 @@ +# userPrincipal management for accounts +# +# Copyright Alejandro Escanero Blanco aescanero@gmail.com 2012 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import samba.getopt as options +import ldb +import re +from samba import provision +from samba.samdb import SamDB +from samba.auth import system_session +from samba.netcmd.common import _get_user_realm_domain +from samba.netcmd import ( + Command, + CommandError, + SuperCommand, + Option + ) + + +class cmd_upn_show(Command): + """LiSi su médico le dice que se vaya de España por culpa del estres?st userPrincipalName of a user account. + +The user can either be specified by their sAMAccountName or using the +--filter option. + +The command may be run from the root userid or another authorized userid. +The -H or --URL= option can be used to execute the command on a remote server. + +Example1: +samba-tool user upn show User1 + +Example1 shows how to show the userPrincipalname attributes of an account. +The username or sAMAccountName is specified using the --filter= paramter and +the username in this example is User1. + +""" + + synopsis = "%prog [options]" + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "credopts": options.CredentialsOptions, + "versionopts": options.VersionOptions, + } + + takes_options = [ + Option("-H", "--URL", help="LDB URL for database or target server", + type=str, + metavar="URL", dest="H"), + Option("--filter", help="LDAP Filter to set upn on", type=str), + ] + + takes_args = ["username"] + + def run(self, username=None, sambaopts=None, credopts=None, + versionopts=None, H=None, filter=None): + if username is None and filter is None: + raise CommandError( + "Either the username or '--filter' must be specified!") + + if filter is None: + filter = "(&(objectClass=user)(sAMAccountName=%s))" \ + % (ldb.binary_encode(username)) + + lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp) + + samdb = SamDB(url=H, session_info=system_session(), + credentials=creds, lp=lp) + + domain_dn = samdb.domain_dn() + res = samdb.search(domain_dn, scope=ldb.SCOPE_SUBTREE, + expression=filter, + attrs=["userPrincipalName"]) + + if len(res) == 0: + raise CommandError("Failed to find user '%s'" + % (username or filter)) + + if "userPrincipalName" in res[0]: + self.outf.write("%s\n" % res[0]["userPrincipalName"]) + + +class cmd_upn_set(Command): + """Add the userPrincipalName to a user account. + +The user can either be specified by their sAMAccountName or using the +--filter option. + +The command may be run from the root userid or another authorized userid. +The -H or --URL= option can be used to execute the command on a remote server. + +Example1: +samba-tool user upn set User1 LOGIN@DOMAINFQDN +--URL=ldap://samba.samdom.example.com --username=administrator +--password=passw1rd + +Example1 shows how to set a userPrincipalname of an account in a remote LDAP +server. The --URL parameter is used to specify the remote target server. +The --username= and --password= options are used to pass the username and +password of a user that exists on the remote server and is authorized to +update that server. + +Example2: +samba-tool user upn set User1 LOGIN@DOMAINFQDN + +Example2 shows how to set the userPrincipalname of an account. The username +or sAMAccountName is specified using the --filter= paramter and the username +in this example is User1. +""" + + synopsis = "%prog [options]" + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "credopts": options.CredentialsOptions, + "versionopts": options.VersionOptions, + } + + takes_options = [ + Option("-H", "--URL", help="LDB URL for database or target server", + type=str, + metavar="URL", dest="H"), + Option("--filter", help="LDAP Filter to set upn on", type=str), + ] + + takes_args = ["username", "upn"] + + def run(self, username=None, upn=None, sambaopts=None, credopts=None, + versionopts=None, H=None, filter=None): + if username is None and filter is None: + raise CommandError( + "Either the username or '--filter' must be specified!") + + if filter is None: + filter = "(&(objectClass=user)(sAMAccountName=%s))" \ + % (ldb.binary_encode(username)) + + lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp) + + samdb = SamDB(url=H, session_info=system_session(), + credentials=creds, lp=lp) + + if upn is None: + raise CommandError("Param UserPrincipalName is not defined") + + domain_dn = samdb.domain_dn() + res = samdb.search(domain_dn, scope=ldb.SCOPE_SUBTREE, + expression=filter, + attrs=["userPrincipalName"]) + + if len(res) == 0: + raise CommandError("Failed to find user '%s'" % + (username or filter)) + + upnsuffix_check(samdb, upn) + + try: + samdb.setupn(filter, upn) + except Exception, msg: + raise CommandError( + "Failed to set userPrincipalName for user '%s': %s" % ( + username or filter, msg)) + self.outf.write("Set UserPrincipalName %s for user '%s' .\n" % ( + upn, username or filter)) + + +class cmd_upn_delete(Command): + """Remove userPrincipalName of a user account. + +The user can either be specified by their sAMAccountName or using the --filter +option. + +The command may be run from the root userid or another authorized userid. +The -H or --URL= option can be used to execute the command on a remote server. + +Example1: +samba-tool user upn delete User1 LOGIN@DOMAINFQDN + +Example1 shows how to remove userPrincipalname of an account. +The username or sAMAccountName is specified using the --filter= paramter and +the username in this example is User1. + +""" + + synopsis = "%prog [options]" + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "credopts": options.CredentialsOptions, + "versionopts": options.VersionOptions, + } + + takes_options = [ + Option("-H", "--URL", help="LDB URL for database or target server", + type=str, + metavar="URL", dest="H"), + Option("--filter", help="LDAP Filter to set upn on", type=str), + ] + + takes_args = ["username"] + + def run(self, username=None, sambaopts=None, credopts=None, + versionopts=None, H=None, filter=None): + if username is None and filter is None: + raise CommandError( + "Either the username or '--filter' must be specified!") + + if filter is None: + filter = "(&(objectClass=user)(sAMAccountName=%s))" % \ + (ldb.binary_encode(username)) + + lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp) + + samdb = SamDB(url=H, session_info=system_session(), + credentials=creds, lp=lp) + + domain_dn = samdb.domain_dn() + res = samdb.search(domain_dn, scope=ldb.SCOPE_SUBTREE, + expression=filter, + attrs=["userPrincipalName"]) + + if len(res) == 0: + raise CommandError("Failed to find user '%s'" + % (username or filter)) + + if not "userPrincipalName" in res[0]: + raise CommandError( + "Failed: No userPrincipalName defined in %s\n" + % username) + + try: + samdb.delupn(filter) + except Exception, msg: + raise CommandError( + "Failed to remove userPrincipalName for user '%s': %s" % ( + username or filter, msg)) + + self.outf.write("Removed UserPrincipalName for user '%s' .\n" % ( + username or filter)) + + +class upnsuffix_check(): + + def __init__(self, samdb=None, upn=None): + if upn is None or samdb is None: + raise CommandError( + "Params in check upnsuffix check is not defined") + + upn_realm = None + m = re.match(r"^[A-Za-z0-9\.\+_-]+@([A-Za-z0-9\._-]+\.[a-zA-Z]*)$", + upn) + if not m: + raise UpnNotValidFormatException( + "Param UserPrincipalName has no valid format" + ) + else: + upn_realm = m.group(1) + + if not upn_realm == samdb.domain_dns_name(): + res = samdb.search(samdb.domain_dn(), scope=ldb.SCOPE_SUBTREE, + expression="(&(objectClass=crossRefContainer)(cn=Partitions))", + attrs=["uPNSuffixes"]) + + if len(res) == 0: + raise UpnNotValidAlternateException( + "Failed to find a alternative user principal name for \ +realm: %s" % (upn_realm)) + + alternate_upn = False + + for l in res: + if l["uPNSuffixes"] == upn_realm: + alternate_upn = True + + if alternate_upn is False: + raise UpnNotValidAlternateException( + "Failed to find a alternative user principal name for \ +realm: %s" % (upn_realm)) + + +class UpnException(Exception): + """Base element for Sites errors""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "UpnException: " + self.value + + +class UpnNotValidFormatException(UpnException): + """Raised when User Principal Name has not valid format.""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "UpnNotValidFormatException: " + self.value + + +class UpnNotValidAlternateException(UpnException): + """Raised when User Principal Name Suffix isn't fount.""" + + def __init__(self, value): + self.value = value + + def __str__(self): + return "UpnNotValidAlternateException: " + self.value + + +class cmd_upn(SuperCommand): + """User Principal Name (UPN) management.""" + + subcommands = {} + subcommands["set"] = cmd_upn_set() + subcommands["show"] = cmd_upn_show() + subcommands["delete"] = cmd_upn_delete() diff --git a/python/samba/netcmd/user.py b/python/samba/netcmd/user.py index b98ec34..19bc752 100644 --- a/python/samba/netcmd/user.py +++ b/python/samba/netcmd/user.py @@ -36,6 +36,13 @@ from samba.netcmd import ( SuperCommand, Option, ) +from samba.netcmd.upn import ( + cmd_upn, + upnsuffix_check, + UpnException, + UpnNotValidFormatException, + UpnNotValidAlternateException + ) class cmd_user_create(Command): @@ -91,6 +98,9 @@ Example4 shows how to create a new user with Unix UID, GID and login-shell set f type=str), Option("--surname", help="User's surname", type=str), Option("--given-name", help="User's given name", type=str), + Option("--upn", + help="User Principal Name in place of username@REALM", type=str), + Option("--no-upn", help="No User Principal Name", action="store_true"), Option("--initials", help="User's initials", type=str), Option("--profile-path", help="User's profile path", type=str), Option("--script-path", help="User's logon script path", type=str), @@ -125,12 +135,18 @@ Example4 shows how to create a new user with Unix UID, GID and login-shell set f def run(self, username, password=None, credopts=None, sambaopts=None, versionopts=None, H=None, must_change_at_next_login=False, random_password=False, use_username_as_cn=False, userou=None, - surname=None, given_name=None, initials=None, profile_path=None, - script_path=None, home_drive=None, home_directory=None, - job_title=None, department=None, company=None, description=None, + surname=None, given_name=None, upn=None, initials=None, + profile_path=None, script_path=None, home_drive=None, + home_directory=None, no_upn=False, job_title=None, + department=None, company=None, description=None, mail_address=None, internet_address=None, telephone_number=None, physical_delivery_office=None, rfc2307_from_nss=False, - uid=None, uid_number=None, gid_number=None, gecos=None, login_shell=None): + uid=None, uid_number=None, gid_number=None, gecos=None, + login_shell=None): + + if upn is not None and no_upn: + raise CommandError( + "Can't use Options --upn and --no-upn at the same time") if random_password: password = generate_random_password(128, 255) @@ -167,16 +183,19 @@ Example4 shows how to create a new user with Unix UID, GID and login-shell set f try: samdb = SamDB(url=H, session_info=system_session(), credentials=creds, lp=lp) + if upn is not None: + upnsuffix_check(samdb, upn) samdb.newuser(username, password, force_password_change_at_next_login_req=must_change_at_next_login, - useusernameascn=use_username_as_cn, userou=userou, surname=surname, givenname=given_name, initials=initials, + useusernameascn=use_username_as_cn, userou=userou, surname=surname, givenname=given_name, upn=upn, initials=initials, profilepath=profile_path, homedrive=home_drive, scriptpath=script_path, homedirectory=home_directory, jobtitle=job_title, department=department, company=company, description=description, - mailaddress=mail_address, internetaddress=internet_address, + mailaddress=mail_address, internetaddress=internet_address, no_upn=no_upn, telephonenumber=telephone_number, physicaldeliveryoffice=physical_delivery_office, uid=uid, uidnumber=uid_number, gidnumber=gid_number, gecos=gecos, loginshell=login_shell) + except UpnException, e: + raise CommandError(str(e)) except Exception, e: raise CommandError("Failed to add user '%s': " % username, e) - self.outf.write("User '%s' created successfully\n" % username) @@ -601,5 +620,6 @@ class cmd_user(SuperCommand): subcommands["enable"] = cmd_user_enable() subcommands["list"] = cmd_user_list() subcommands["setexpiry"] = cmd_user_setexpiry() + subcommands["upn"] = cmd_upn() subcommands["password"] = cmd_user_password() subcommands["setpassword"] = cmd_user_setpassword() diff --git a/python/samba/samdb.py b/python/samba/samdb.py index 2dfc839..650a79d 100644 --- a/python/samba/samdb.py +++ b/python/samba/samdb.py @@ -286,12 +286,13 @@ member: %s def newuser(self, username, password, force_password_change_at_next_login_req=False, useusernameascn=False, userou=None, surname=None, givenname=None, - initials=None, profilepath=None, scriptpath=None, homedrive=None, - homedirectory=None, jobtitle=None, department=None, company=None, - description=None, mailaddress=None, internetaddress=None, - telephonenumber=None, physicaldeliveryoffice=None, sd=None, - setpassword=True, uidnumber=None, gidnumber=None, gecos=None, - loginshell=None, uid=None): + upn=None, initials=None, profilepath=None, scriptpath=None, + homedrive=None, homedirectory=None, jobtitle=None, department=None, + company=None, description=None, mailaddress=None, + internetaddress=None, no_upn=False, telephonenumber=None, + physicaldeliveryoffice=None, sd=None, setpassword=True, + uidnumber=None, gidnumber=None, gecos=None, loginshell=None, + uid=None): """Adds a new user with additional parameters :param username: Name of the new user @@ -302,6 +303,8 @@ member: %s :param userou: Object container (without domainDN postfix) for new user :param surname: Surname of the new user :param givenname: First name of the new user + :param upn: UserPrincipalName of the new user + :param no-upn: The user has no UserPrincipalName :param initials: Initials of the new user :param profilepath: Profile path of the new user :param scriptpath: Logon script path of the new user @@ -346,7 +349,6 @@ member: %s # fills in the default informations ldbmessage = {"dn": user_dn, "sAMAccountName": username, - "userPrincipalName": user_principal_name, "objectClass": "user"} if surname is not None: @@ -355,6 +357,11 @@ member: %s if givenname is not None: ldbmessage["givenName"] = givenname + if upn is not None: + ldbmessage["userPrincipalName"] = upn + elif no_upn is False or no_upn is None: + ldbmessage["userPrincipalName"] = user_principal_name + if displayname is not "": ldbmessage["displayName"] = displayname ldbmessage["name"] = displayname @@ -538,6 +545,67 @@ accountExpires: %u else: self.transaction_commit() + def setupn(self, search_filter, userPrincipalName): + """Set a userPrincipalName for a user + + :param search_filter: LDAP filter to find the user (eg + samaccountname=name) + :param upn: userPrincipalName in form LOGIN@DOMAINFQDN + """ + self.transaction_start() + try: + res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE, + expression=search_filter, + attrs=["userPrincipalName"]) + + if len(res) == 0: + raise Exception('Unable to find user "%s"' % search_filter) + + user_dn = res[0].dn + + setexp = """ +dn: %s +changetype: modify +replace: userPrincipalName +userPrincipalName: %s +""" % (user_dn, userPrincipalName) + + self.modify_ldif(setexp) + except: + self.transaction_cancel() + raise + else: + self.transaction_commit() + + def delupn(self, search_filter): + """Delete a userPrincipalName from a user + + :param search_filter: LDAP filter to find the user (eg + samaccountname=name) + """ + self.transaction_start() + try: + res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE, + expression=search_filter, + attrs=["userPrincipalName"]) + + if len(res) == 0: + raise Exception('Unable to find user "%s"' % search_filter) + + user_dn = res[0].dn + setexp = """ +dn: %s +changetype: modify +delete: userPrincipalName +""" % (user_dn) + + self.modify_ldif(setexp) + except: + self.transaction_cancel() + raise + else: + self.transaction_commit() + def set_domain_sid(self, sid): """Change the domain SID used by this LDB. diff --git a/python/samba/tests/samba_tool/user.py b/python/samba/tests/samba_tool/user.py index 645eb40..fcd0942 100644 --- a/python/samba/tests/samba_tool/user.py +++ b/python/samba/tests/samba_tool/user.py @@ -18,6 +18,7 @@ import os import time import ldb +from samba.tests import env_loadparm from samba.tests.samba_tool.base import SambaToolCmdTest from samba import ( nttime2unix, @@ -98,6 +99,11 @@ class UserCmdTestCase(SambaToolCmdTest): self.assertEquals("%s" % found.get("cn"), "%(name)s" % user) self.assertEquals("%s" % found.get("name"), "%(name)s" % user) + lp = env_loadparm() + realm = lp.get("realm") + upn = "%s@%s" % (user["name"], realm) + self.assertEquals(str(found.get("userPrincipalName")).lower(), + str(upn).lower()) def test_setpassword(self): @@ -279,6 +285,73 @@ class UserCmdTestCase(SambaToolCmdTest): self._check_posix_user(user) self.runsubcmd("user", "delete", user["name"]) + def test_setupn(self): + newupn = "test@samba.example.com" + upnlist = {} + for user in self.users: + found = self._find_user(user["name"]) + upnlist[user["name"]] = found.get("userPrincipalName") + + (result, out, err) = self.runsubcmd("user", "upn", "set", + user["name"], + "%s" % newupn, + "-H", "ldap://%s" % os.environ["DC_SERVER"], + "-U%s%%%s" % (os.environ["DC_USERNAME"], + os.environ["DC_PASSWORD"])) + + found = self._find_user(user["name"]) + + self.assertEquals(str(found.get("userPrincipalName")).lower(), + newupn) + + for user in self.users: + (result, out, err) = self.runsubcmd("user", "upn", "delete", + user["name"], + "-H", "ldap://%s" % os.environ["DC_SERVER"], + "-U%s%%%s" % (os.environ["DC_USERNAME"], + os.environ["DC_PASSWORD"])) + found = self._find_user(user["name"]) + + self.assertEquals(found.get("userPrincipalName"), None) + + for user in self.users: + upn = upnlist[user["name"]] + if upn is None: + self.assertIn("UPN '%s' not created successfully" % + user["name"], out) + + (result, out, err) = self.runsubcmd("user", "upn", "set", + user["name"], + "%s" % upn, + "-U%s%%%s" % (os.environ["DC_USERNAME"], + os.environ["DC_PASSWORD"])) + + found = self._find_user(user["name"]) + + self.assertEquals(found.get("userPrincipalName"), upn) + + for user in self.users: + (result, out, err) = self.runsubcmd("user", "upn", "delete", + user["name"], + "-U%s%%%s" % (os.environ["DC_USERNAME"], + os.environ["DC_PASSWORD"])) + + found = self._find_user(user["name"]) + + self.assertEquals(found.get("userPrincipalName"), None) + + for user in self.users: + upn = upnlist[user["name"]] + (result, out, err) = self.runsubcmd("user", "upn", "set", + user["name"], + "%s" % upn, + "-U%s%%%s" % (os.environ["DC_USERNAME"], + os.environ["DC_PASSWORD"])) + + found = self._find_user(user["name"]) + + self.assertEquals(found.get("userPrincipalName"), upn) + def _randomUser(self, base={}): """create a user with random attribute values, you can specify base attributes""" user = { @@ -371,3 +444,4 @@ class UserCmdTestCase(SambaToolCmdTest): return userlist[0] else: return None + diff --git a/python/samba/upgrade.py b/python/samba/upgrade.py index 532e1de..98985c31 100644 --- a/python/samba/upgrade.py +++ b/python/samba/upgrade.py @@ -128,6 +128,31 @@ def add_posix_attrs(logger, samdb, sid, name, nisdomain, xid_type, home=None, 'Could not add posix attrs for AD entry for sid=%s, (%s)', str(sid), str(e)) + +def add_userPrincipalName(logger, samdb, sid, name, realm): + """Add userPrincipalName for the user + + :param samdb: Samba4 sam.ldb database + :param sid: user/group sid + :param name: user/group name + :param realm: fqdn domain name + """ + user_principal_name = "%s@%s" % (name, realm) + + try: + m = ldb.Message() + m.dn = ldb.Dn(samdb, "" % str(sid)) + m['userPrincipalName'] = ldb.MessageElement( + str(user_principal_name), + ldb.FLAG_MOD_REPLACE, 'userPrincipalName') + + samdb.modify(m) + except ldb.LdbError, e: + logger.warn( + 'Could not add userPrincipalName attr for \ + AD entry for sid=%s, (%s)', str(sid), str(e)) + + def add_ad_posix_idmap_entry(samdb, sid, xid, xid_type, logger): """Create idmap entry @@ -550,7 +575,7 @@ def get_posix_attr_from_ldap_backend(logger, ldb_object, base_dn, user, attr): def upgrade_from_samba3(samba3, logger, targetdir, session_info=None, - useeadb=False, dns_backend=None, use_ntvfs=False): + useeadb=False, dns_backend=None, use_ntvfs=False, no_upn=False): """Upgrade from samba3 database to samba4 AD database :param samba3: samba3 object @@ -747,13 +772,13 @@ Please fix this account before attempting to upgrade again admin_user = username try: - group_memberships = s3db.enum_group_memberships(user); + group_memberships = s3db.enum_group_memberships(user) for group in group_memberships: if str(group) in groupmembers: if user.user_sid not in groupmembers[str(group)]: groupmembers[str(group)].append(user.user_sid) else: - groupmembers[str(group)] = [user.user_sid]; + groupmembers[str(group)] = [user.user_sid] except passdb.error, e: logger.warn("Ignoring group memberships of '%s' %s: %s", username, user.user_sid, e) @@ -901,8 +926,17 @@ Please fix this account before attempting to upgrade again # Ignore uninitialized groups (gid = -1) if g.gid != -1: add_group_from_mapping_entry(result.samdb, g, logger) - add_ad_posix_idmap_entry(result.samdb, g.sid, g.gid, "ID_TYPE_GID", logger) - add_posix_attrs(samdb=result.samdb, sid=g.sid, name=g.nt_name, nisdomain=domainname.lower(), xid_type="ID_TYPE_GID", logger=logger) + add_ad_posix_idmap_entry(result.samdb, g.sid, g.gid, + "ID_TYPE_GID", logger) + add_posix_attrs(samdb=result.samdb, sid=g.sid, name=g.nt_name, + nisdomain=domainname.lower(), xid_type="ID_TYPE_GID", + logger=logger) + if (no_upn is not True) and (userdata[username].acct_ctrl + & samr.ACB_NORMAL): + add_userPrincipalName(samdb=result.samdb, + sid=userdata[username].user_sid, + name=username, realm=realm) + except: # We need this, so that we do not give even more errors due to not cancelling the transaction -- 1.8.3.2