lsa4: Fix Coverity ID 1499410
[Samba.git] / python / samba / subnets.py
blobef739505a2e4cf58c0f726719f03decc5c11e7f5
1 # Add/remove subnets to sites.
3 # Copyright (C) Catalyst.Net Ltd 2015
4 # Copyright Matthieu Patou <mat@matws.net> 2011
6 # Catalyst.Net's contribution was written by Douglas Bagnall
7 # <douglas.bagnall@catalyst.net.nz>.
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
23 import ldb
24 from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, LdbError
25 from . sites import SiteNotFoundException
28 class SubnetException(Exception):
29 """Base element for Subnet errors"""
30 pass
33 class SubnetNotFound(SubnetException):
34 """The subnet requested does not exist."""
35 pass
38 class SubnetAlreadyExists(SubnetException):
39 """The subnet being added already exists."""
40 pass
43 class SubnetInvalid(SubnetException):
44 """The subnet CIDR is invalid."""
45 pass
48 class SiteNotFound(SubnetException):
49 """The site to be used for the subnet does not exist."""
50 pass
53 def create_subnet(samdb, configDn, subnet_name, site_name):
54 """Create a subnet and associate it with a site.
56 :param samdb: A samdb connection
57 :param configDn: The DN of the configuration partition
58 :param subnet_name: name of the subnet to create (a CIDR range)
59 :return: None
60 :raise SubnetAlreadyExists: if the subnet to be created already exists.
61 :raise SiteNotFound: if the site does not exist.
62 """
63 ret = samdb.search(base=configDn, scope=ldb.SCOPE_SUBTREE,
64 expression='(&(objectclass=Site)(cn=%s))' %
65 ldb.binary_encode(site_name))
66 if len(ret) != 1:
67 raise SiteNotFound('A site with the name %s does not exist' %
68 site_name)
69 dn_site = ret[0].dn
71 if not isinstance(subnet_name, str):
72 raise SubnetInvalid("%s is not a valid subnet (not a string)" % subnet_name)
74 dnsubnet = ldb.Dn(samdb, "CN=Subnets,CN=Sites")
75 try:
76 dnsubnet.add_base(configDn)
77 except ldb.LdbError:
78 raise SubnetException("dnsubnet.add_base() failed")
79 try:
80 dnsubnet.add_child("CN=X")
81 except ldb.LdbError:
82 raise SubnetException("dnsubnet.add_child() failed")
83 dnsubnet.set_component(0, "CN", subnet_name)
85 try:
86 m = ldb.Message()
87 m.dn = dnsubnet
88 m["objectclass"] = ldb.MessageElement("subnet", FLAG_MOD_ADD,
89 "objectclass")
90 m["siteObject"] = ldb.MessageElement(str(dn_site), FLAG_MOD_ADD,
91 "siteObject")
92 samdb.add(m)
93 except ldb.LdbError as e:
94 (enum, estr) = e.args
95 if enum == ldb.ERR_INVALID_DN_SYNTAX:
96 raise SubnetInvalid("%s is not a valid subnet: %s" % (subnet_name, estr))
97 elif enum == ldb.ERR_ENTRY_ALREADY_EXISTS:
98 # Subnet collisions are checked by exact match only, not
99 # overlapping range. This won't stop you creating
100 # 10.1.1.0/24 when there is already 10.1.0.0/16, or
101 # prevent you from having numerous IPv6 subnets that refer
102 # to the same range (e.g 5::0/16, 5::/16, 5:0:0::/16).
103 raise SubnetAlreadyExists('A subnet with the CIDR %s already exists'
104 % subnet_name)
105 else:
106 raise
109 def delete_subnet(samdb, configDn, subnet_name):
110 """Delete a subnet.
112 :param samdb: A samdb connection
113 :param configDn: The DN of the configuration partition
114 :param subnet_name: Name of the subnet to delete
115 :return: None
116 :raise SubnetNotFound: if the subnet to be deleted does not exist.
118 dnsubnet = ldb.Dn(samdb, "CN=Subnets,CN=Sites")
119 try:
120 dnsubnet.add_base(configDn)
121 except ldb.LdbError:
122 raise SubnetException("dnsubnet.add_base() failed")
123 try:
124 dnsubnet.add_child("CN=X")
125 except ldb.LdbError:
126 raise SubnetException("dnsubnet.add_child() failed")
127 dnsubnet.set_component(0, "CN", subnet_name)
129 try:
130 ret = samdb.search(base=dnsubnet, scope=ldb.SCOPE_BASE,
131 expression="objectClass=subnet")
132 if len(ret) != 1:
133 raise SubnetNotFound('Subnet %s does not exist' % subnet_name)
134 except LdbError as e1:
135 (enum, estr) = e1.args
136 if enum == ldb.ERR_NO_SUCH_OBJECT:
137 raise SubnetNotFound('Subnet %s does not exist' % subnet_name)
139 samdb.delete(dnsubnet)
142 def rename_subnet(samdb, configDn, subnet_name, new_name):
143 """Rename a subnet.
145 :param samdb: A samdb connection
146 :param configDn: The DN of the configuration partition
147 :param subnet_name: Name of the subnet to rename
148 :param new_name: New name for the subnet
149 :return: None
150 :raise SubnetNotFound: if the subnet to be renamed does not exist.
151 :raise SubnetExists: if the subnet to be created already exists.
153 dnsubnet = ldb.Dn(samdb, "CN=Subnets,CN=Sites")
154 try:
155 dnsubnet.add_base(configDn)
156 except ldb.LdbError:
157 raise SubnetException("dnsubnet.add_base() failed")
158 try:
159 dnsubnet.add_child("CN=X")
160 except ldb.LdbError:
161 raise SubnetException("dnsubnet.add_child() failed")
162 dnsubnet.set_component(0, "CN", subnet_name)
164 newdnsubnet = ldb.Dn(samdb, str(dnsubnet))
165 newdnsubnet.set_component(0, "CN", new_name)
166 try:
167 samdb.rename(dnsubnet, newdnsubnet)
168 except LdbError as e2:
169 (enum, estr) = e2.args
170 if enum == ldb.ERR_NO_SUCH_OBJECT:
171 raise SubnetNotFound('Subnet %s does not exist' % dnsubnet)
172 elif enum == ldb.ERR_ENTRY_ALREADY_EXISTS:
173 raise SubnetAlreadyExists('A subnet with the CIDR %s already exists'
174 % new_name)
175 elif enum == ldb.ERR_INVALID_DN_SYNTAX:
176 raise SubnetInvalid("%s is not a valid subnet: %s" % (new_name,
177 estr))
178 else:
179 raise
182 def set_subnet_site(samdb, configDn, subnet_name, site_name):
183 """Assign a subnet to a site.
185 This dissociates the subnet from its previous site.
187 :param samdb: A samdb connection
188 :param configDn: The DN of the configuration partition
189 :param subnet_name: Name of the subnet
190 :param site_name: Name of the site
191 :return: None
192 :raise SubnetNotFound: if the subnet does not exist.
193 :raise SiteNotFound: if the site does not exist.
196 dnsubnet = ldb.Dn(samdb, "CN=Subnets,CN=Sites")
197 try:
198 dnsubnet.add_base(configDn)
199 except ldb.LdbError:
200 raise SubnetException("dnsubnet.add_base() failed")
201 try:
202 dnsubnet.add_child("CN=X")
203 except ldb.LdbError:
204 raise SubnetException("dnsubnet.add_child() failed")
205 dnsubnet.set_component(0, "CN", subnet_name)
207 try:
208 ret = samdb.search(base=dnsubnet, scope=ldb.SCOPE_BASE,
209 expression="objectClass=subnet")
210 if len(ret) != 1:
211 raise SubnetNotFound('Subnet %s does not exist' % subnet_name)
212 except LdbError as e3:
213 (enum, estr) = e3.args
214 if enum == ldb.ERR_NO_SUCH_OBJECT:
215 raise SubnetNotFound('Subnet %s does not exist' % subnet_name)
217 dnsite = ldb.Dn(samdb, "CN=Sites")
218 try:
219 dnsite.add_base(configDn)
220 except ldb.LdbError:
221 raise SubnetException("dnsite.add_base() failed")
222 try:
223 dnsite.add_child("CN=X")
224 except ldb.LdbError:
225 raise SubnetException("dnsite.add_child() failed")
226 dnsite.set_component(0, "CN", site_name)
228 dnservers = ldb.Dn(samdb, "CN=Servers")
229 dnservers.add_base(dnsite)
231 try:
232 ret = samdb.search(base=dnsite, scope=ldb.SCOPE_BASE,
233 expression="objectClass=site")
234 if len(ret) != 1:
235 raise SiteNotFoundException('Site %s does not exist' % site_name)
236 except LdbError as e4:
237 (enum, estr) = e4.args
238 if enum == ldb.ERR_NO_SUCH_OBJECT:
239 raise SiteNotFoundException('Site %s does not exist' % site_name)
241 siteDn = str(ret[0].dn)
243 m = ldb.Message()
244 m.dn = dnsubnet
245 m["siteObject"] = ldb.MessageElement(siteDn, FLAG_MOD_REPLACE,
246 "siteObject")
247 samdb.modify(m)