scripting/samba_upgradedns: Tighten up exception and attribute list handling
[metze/samba/wip.git] / source4 / scripting / bin / samba_upgradedns
index 5a335a91f4316074159898d067011dbd3bc4369d..306f4d60378dfca419d4b668420381cfe32a03f4 100755 (executable)
@@ -26,7 +26,7 @@ import grp
 from base64 import b64encode
 import shlex
 
-sys.path.insert(0, 'bin/python')
+sys.path.insert(0, "bin/python")
 
 import ldb
 import samba
@@ -91,7 +91,7 @@ def fix_names(pnames):
     names.domaindn = pnames.domaindn[0]
     names.configdn = pnames.configdn[0]
     names.schemadn = pnames.schemadn[0]
-    names.wheel_gid = pnames.wheel_gid[0]
+    names.root_gid = pnames.root_gid
     names.serverdn = str(pnames.serverdn)
     return names
 
@@ -238,8 +238,8 @@ if __name__ == '__main__':
     parser.add_option_group(credopts)
 
     parser.add_option("--dns-backend", type="choice", metavar="<BIND9_DLZ|SAMBA_INTERNAL>",
-                      choices=["SAMBA_INTERNAL", "BIND9_DLZ"], default="BIND9_DLZ",
-                      help="The DNS server backend, default BIND9_DLZ")
+                      choices=["SAMBA_INTERNAL", "BIND9_DLZ"], default="SAMBA_INTERNAL",
+                      help="The DNS server backend, default SAMBA_INTERNAL")
     parser.add_option("--migrate", type="choice", metavar="<yes|no>",
                       choices=["yes","no"], default="yes",
                       help="Migrate existing zone data, default yes")
@@ -248,7 +248,7 @@ if __name__ == '__main__':
     opts = parser.parse_args()[0]
 
     if opts.dns_backend is None:
-        opts.dns_backend = 'DLZ_BIND9'
+        opts.dns_backend = 'SAMBA_INTERNAL'
 
     if opts.migrate:
         autofill = False
@@ -278,27 +278,6 @@ if __name__ == '__main__':
         logger.error("Cannot create AD based DNS for OS level < 2003")
         sys.exit(1)
 
-    logger.info("Looking up IPv4 addresses")
-    hostip = interface_ips_v4(lp)
-    try:
-        hostip.remove('127.0.0.1')
-    except ValueError:
-        pass
-    if not hostip:
-        logger.error("No IPv4 addresses found")
-        sys.exit(1)
-    else:
-        hostip = hostip[0]
-        logger.debug("IPv4 addresses: %s" % hostip)
-
-    logger.info("Looking up IPv6 addresses")
-    hostip6 = interface_ips_v6(lp, linklocal=False)
-    if not hostip6:
-        hostip6 = None
-    else:
-        hostip6 = hostip6[0]
-        logger.debug("IPv6 addresses: %s" % hostip6)
-
     domaindn = names.domaindn
     forestdn = names.rootdn
 
@@ -319,7 +298,7 @@ if __name__ == '__main__':
                               expression='(sAMAccountName=DnsAdmins)',
                               attrs=['objectSid'])
         dnsadmins_sid = ndr_unpack(security.dom_sid, msg[0]['objectSid'][0])
-    except Exception, e:
+    except IndexError:
         logger.info("Adding DNS accounts")
         add_dns_accounts(ldbs.sam, domaindn)
         dnsadmins_sid = get_dnsadmins_sid(ldbs.sam, domaindn)
@@ -349,8 +328,30 @@ if __name__ == '__main__':
         msg = ldbs.sam.search(base=names.configdn, scope=ldb.SCOPE_DEFAULT,
                               expression=expression, attrs=['nCName'])
         ncname = msg[0]['nCName'][0]
-    except Exception, e:
+    except IndexError:
         logger.info("Creating DNS partitions")
+
+        logger.info("Looking up IPv4 addresses")
+        hostip = interface_ips_v4(lp)
+        try:
+            hostip.remove('127.0.0.1')
+        except ValueError:
+            pass
+        if not hostip:
+            logger.error("No IPv4 addresses found")
+            sys.exit(1)
+        else:
+            hostip = hostip[0]
+            logger.debug("IPv4 addresses: %s" % hostip)
+
+        logger.info("Looking up IPv6 addresses")
+        hostip6 = interface_ips_v6(lp, linklocal=False)
+        if not hostip6:
+            hostip6 = None
+        else:
+            hostip6 = hostip6[0]
+        logger.debug("IPv6 addresses: %s" % hostip6)
+
         create_dns_partitions(ldbs.sam, domainsid, names, domaindn, forestdn,
                           dnsadmins_sid)
 
@@ -390,62 +391,82 @@ if __name__ == '__main__':
             for nc in ncs:
                 partial_nclist.append(nc)
 
-        modified = False
+        modified_master = False
+        modified_partial = False
         for nc in dns_nclist:
             if nc not in master_nclist:
                 master_nclist.append(nc)
-                modified = True
+                modified_master = True
             if nc in partial_nclist:
                 partial_nclist.remove(nc)
-                modified = True
+                modified_partial = True
 
-        if modified:
+        if modified_master or modified_partial:
             logger.debug("Updating msDS-hasMasterNCs and hasPartialReplicaNCs attributes")
-            msg["msDS-hasMasterNCs"] = ldb.MessageElement(master_nclist,
-                                                          ldb.FLAG_MOD_REPLACE,
-                                                          "msDS-hasMasterNCs")
-            msg["hasPartialReplicaNCs"] = ldb.MessageElement(partial_nclist,
-                                                             ldb.FLAG_MOD_REPLACE,
-                                                             "hasPartialReplicaNCs")
-            ldbs.sam.modify(msg)
+            m = ldb.Message()
+            m.dn = msg.dn
+            if modified_master:
+                m["msDS-hasMasterNCs"] = ldb.MessageElement(master_nclist,
+                                                            ldb.FLAG_MOD_REPLACE,
+                                                            "msDS-hasMasterNCs")
+            if modified_partial:
+                if partial_nclist:
+                    m["hasPartialReplicaNCs"] = ldb.MessageElement(partial_nclist,
+                                                                   ldb.FLAG_MOD_REPLACE,
+                                                                   "hasPartialReplicaNCs")
+                else:
+                    m["hasPartialReplicaNCs"] = ldb.MessageElement(ncs,
+                                                                   ldb.FLAG_MOD_DELETE,
+                                                                   "hasPartialReplicaNCs")
+            ldbs.sam.modify(m)
     except Exception:
         raise
 
-    # Check if dns-HOSTNAME account exists and create it if required
-    try:
-        dn = 'samAccountName=dns-%s,CN=Principals' % hostname
-        msg = ldbs.secrets.search(expression='(dn=%s)' % dn, attrs=['secret'])
-        dnssecret = msg[0]['secret'][0]
-    except Exception:
-        logger.info("Adding dns-%s account" % hostname)
-
+    # Special stuff for DLZ backend
+    if opts.dns_backend == "BIND9_DLZ":
+        # Check if dns-HOSTNAME account exists and create it if required
         try:
-            msg = ldbs.sam.search(base=domaindn, scope=ldb.SCOPE_DEFAULT,
+            dn = 'samAccountName=dns-%s,CN=Principals' % hostname
+            msg = ldbs.secrets.search(expression='(dn=%s)' % dn, attrs=['secret'])
+            dnssecret = msg[0]['secret'][0]
+        except IndexError:
+
+            logger.info("Adding dns-%s account" % hostname)
+
+            try:
+                msg = ldbs.sam.search(base=domaindn, scope=ldb.SCOPE_DEFAULT,
+                                      expression='(sAMAccountName=dns-%s)' % (hostname),
+                                      attrs=[])
+                dn = msg[0].dn
+                ldbs.sam.delete(dn)
+            except IndexError:
+                pass
+
+            dnspass = samba.generate_random_password(128, 255)
+            setup_add_ldif(ldbs.sam, setup_path("provision_dns_add_samba.ldif"), {
+                    "DNSDOMAIN": dnsdomain,
+                    "DOMAINDN": domaindn,
+                    "DNSPASS_B64": b64encode(dnspass.encode('utf-16-le')),
+                    "HOSTNAME" : hostname,
+                    "DNSNAME" : dnsname }
+                           )
+
+            res = ldbs.sam.search(base=domaindn, scope=ldb.SCOPE_DEFAULT,
                                   expression='(sAMAccountName=dns-%s)' % (hostname),
-                                  attrs=['clearTextPassword'])
-            dn = msg[0].dn
-            ldbs.sam.delete(dn)
-        except Exception:
-            pass
-
-        dnspass = samba.generate_random_password(128, 255)
-        setup_add_ldif(ldbs.sam, setup_path("provision_dns_add_samba.ldif"), {
-                       "DNSDOMAIN": dnsdomain,
-                       "DOMAINDN": domaindn,
-                       "DNSPASS_B64": b64encode(dnspass.encode('utf-16-le')),
-                       "HOSTNAME" : hostname,
-                       "DNSNAME" : dnsname }
-                       )
-
-        secretsdb_setup_dns(ldbs.secrets, names,
-                            paths.private_dir, realm=names.realm,
-                            dnsdomain=names.dnsdomain,
-                            dns_keytab_path=paths.dns_keytab, dnspass=dnspass)
-    else:
-        logger.info("dns-%s account already exists" % hostname)
+                                  attrs=["msDS-KeyVersionNumber"])
+            if "msDS-KeyVersionNumber" in res[0]:
+                dns_key_version_number = int(res[0]["msDS-KeyVersionNumber"][0])
+            else:
+                dns_key_version_number = None
+
+            secretsdb_setup_dns(ldbs.secrets, names,
+                                paths.private_dir, realm=names.realm,
+                                dnsdomain=names.dnsdomain,
+                                dns_keytab_path=paths.dns_keytab, dnspass=dnspass,
+                                key_version_number=dns_key_version_number)
+        else:
+            logger.info("dns-%s account already exists" % hostname)
 
-    # Special stuff for DLZ backend
-    if opts.dns_backend == "BIND9_DLZ":
         # This forces a re-creation of dns directory and all the files within
         # It's an overkill, but it's easier to re-create a samdb copy, rather
         # than trying to fix a broken copy.
@@ -462,5 +483,33 @@ if __name__ == '__main__':
         logger.info("See %s for an example configuration include file for BIND", paths.namedconf)
         logger.info("and %s for further documentation required for secure DNS "
                     "updates", paths.namedtxt)
+    elif opts.dns_backend == "SAMBA_INTERNAL":
+        # Check if dns-HOSTNAME account exists and delete it if required
+        try:
+            dn_str = 'samAccountName=dns-%s,CN=Principals' % hostname
+            msg = ldbs.secrets.search(expression='(dn=%s)' % dn_str, attrs=[])
+            dn = msg[0].dn
+        except IndexError:
+            dn = None
+
+        if dn is not None:
+            try:
+                ldbs.secrets.delete(dn)
+            except Exception:
+                logger.info("Failed to delete %s from secrets.ldb" % dn)
+
+        try:
+            msg = ldbs.sam.search(base=domaindn, scope=ldb.SCOPE_DEFAULT,
+                                  expression='(sAMAccountName=dns-%s)' % (hostname),
+                                  attrs=[])
+            dn = msg[0].dn
+        except IndexError:
+            dn = None
+
+        if dn is not None:
+            try:
+                ldbs.sam.delete(dn)
+            except Exception:
+                logger.info("Failed to delete %s from sam.ldb" % dn)
 
     logger.info("Finished upgrading DNS")