samba.netcmd: Formatting fixes, break lines.
[metze/samba/wip.git] / source4 / scripting / python / samba / netcmd / dns.py
1 # DNS management tool
2 #
3 # Copyright (C) Amitay Isaacs 2011-2012
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 #
18
19 import samba.getopt as options
20 from struct import pack
21 from socket import inet_ntoa
22 import shlex
23
24 from samba.netcmd import (
25     Command,
26     CommandError,
27     Option,
28     SuperCommand,
29     )
30 from samba.dcerpc import dnsp, dnsserver
31
32
33 def dns_connect(server, lp, creds):
34     binding_str = "ncacn_ip_tcp:%s[sign]" % server
35     dns_conn = dnsserver.dnsserver(binding_str, lp, creds)
36     return dns_conn
37
38
39 def bool_string(flag):
40     if flag == 0:
41         ret = 'FALSE'
42     elif flag == 1:
43         ret = 'TRUE'
44     else:
45         ret = 'UNKNOWN (0x%x)' % flag
46     return ret
47
48
49 def enum_string(module, enum_defs, value):
50     ret = None
51     for e in enum_defs:
52         if value == getattr(module, e):
53             ret = e
54             break
55     if not ret:
56         ret = 'UNKNOWN (0x%x)' % value
57     return ret
58
59
60 def bitmap_string(module, bitmap_defs, value):
61     ret = ''
62     for b in bitmap_defs:
63         if value & getattr(module, b):
64             ret += '%s ' % b
65     if not ret:
66         ret = 'NONE'
67     return ret
68
69
70 def boot_method_string(boot_method):
71     enum_defs = [ 'DNS_BOOT_METHOD_UNINITIALIZED', 'DNS_BOOT_METHOD_FILE',
72                     'DNS_BOOT_METHOD_REGISTRY', 'DNS_BOOT_METHOD_DIRECTORY' ]
73     return enum_string(dnsserver, enum_defs, boot_method)
74
75
76 def name_check_flag_string(check_flag):
77     enum_defs = [ 'DNS_ALLOW_RFC_NAMES_ONLY', 'DNS_ALLOW_NONRFC_NAMES',
78                     'DNS_ALLOW_MULTIBYTE_NAMES', 'DNS_ALLOW_ALL_NAMES' ]
79     return enum_string(dnsserver, enum_defs, check_flag)
80
81
82 def zone_type_string(zone_type):
83     enum_defs = [ 'DNS_ZONE_TYPE_CACHE', 'DNS_ZONE_TYPE_PRIMARY',
84                     'DNS_ZONE_TYPE_SECONDARY', 'DNS_ZONE_TYPE_STUB',
85                     'DNS_ZONE_TYPE_FORWARDER', 'DNS_ZONE_TYPE_SECONDARY_CACHE' ]
86     return enum_string(dnsp, enum_defs, zone_type)
87
88
89 def zone_update_string(zone_update):
90     enum_defs = [ 'DNS_ZONE_UPDATE_OFF', 'DNS_ZONE_UPDATE_SECURE',
91                     'DNS_ZONE_UPDATE_SECURE' ]
92     return enum_string(dnsp, enum_defs, zone_update)
93
94
95 def zone_secondary_security_string(security):
96     enum_defs = [ 'DNS_ZONE_SECSECURE_NO_SECURITY', 'DNS_ZONE_SECSECURE_NS_ONLY',
97                     'DNS_ZONE_SECSECURE_LIST_ONLY', 'DNS_ZONE_SECSECURE_NO_XFER' ]
98     return enum_string(dnsserver, enum_defs, security)
99
100
101 def zone_notify_level_string(notify_level):
102     enum_defs = [ 'DNS_ZONE_NOTIFY_OFF', 'DNS_ZONE_NOTIFY_ALL_SECONDARIES',
103                     'DNS_ZONE_NOTIFY_LIST_ONLY' ]
104     return enum_string(dnsserver, enum_defs, notify_level)
105
106
107 def dp_flags_string(dp_flags):
108     bitmap_defs = [ 'DNS_DP_AUTOCREATED', 'DNS_DP_LEGACY', 'DNS_DP_DOMAIN_DEFAULT',
109                 'DNS_DP_FOREST_DEFAULT', 'DNS_DP_ENLISTED', 'DNS_DP_DELETED' ]
110     return bitmap_string(dnsserver, bitmap_defs, dp_flags)
111
112
113 def zone_flags_string(flags):
114     bitmap_defs = [ 'DNS_RPC_ZONE_PAUSED', 'DNS_RPC_ZONE_SHUTDOWN',
115                     'DNS_RPC_ZONE_REVERSE', 'DNS_RPC_ZONE_AUTOCREATED',
116                     'DNS_RPC_ZONE_DSINTEGRATED', 'DNS_RPC_ZONE_AGING',
117                     'DNS_RPC_ZONE_UPDATE_UNSECURE', 'DNS_RPC_ZONE_UPDATE_SECURE',
118                     'DNS_RPC_ZONE_READONLY']
119     return bitmap_string(dnsserver, bitmap_defs, flags)
120
121
122 def ip4_array_string(array):
123     ret = []
124     if not array:
125         return ret
126     for i in xrange(array.AddrCount):
127         addr = '%s' % inet_ntoa(pack('i', array.AddrArray[i]))
128         ret.append(addr)
129     return ret
130
131
132 def dns_addr_array_string(array):
133     ret = []
134     if not array:
135         return ret
136     for i in xrange(array.AddrCount):
137         if array.AddrArray[i].MaxSa[0] == 0x02:
138             addr = '%d.%d.%d.%d (%d)' % \
139                 tuple(array.AddrArray[i].MaxSa[4:8] + [array.AddrArray[i].MaxSa[3]])
140         elif array.AddrArray[i].MaxSa[0] == 0x17:
141             addr = '%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x (%d)' % \
142                 tuple(array.AddrArray[i].MaxSa[4:20] + [array.AddrArray[i].MaxSa[3]])
143         else:
144             addr = 'UNKNOWN'
145         ret.append(addr)
146     return ret
147
148
149 def dns_type_flag(rec_type):
150     rtype = rec_type.upper()
151     if rtype == 'A':
152         record_type = dnsp.DNS_TYPE_A
153     elif rtype == 'AAAA':
154         record_type = dnsp.DNS_TYPE_AAAA
155     elif rtype == 'PTR':
156         record_type = dnsp.DNS_TYPE_PTR
157     elif rtype == 'NS':
158         record_type = dnsp.DNS_TYPE_NS
159     elif rtype == 'CNAME':
160         record_type = dnsp.DNS_TYPE_CNAME
161     elif rtype == 'SOA':
162         record_type = dnsp.DNS_TYPE_SOA
163     elif rtype == 'MX':
164         record_type = dnsp.DNS_TYPE_MX
165     elif rtype == 'SRV':
166         record_type = dnsp.DNS_TYPE_SRV
167     elif rtype == 'TXT':
168         record_type = dnsp.DNS_TYPE_TXT
169     elif rtype == 'ALL':
170         record_type = dnsp.DNS_TYPE_ALL
171     else:
172         raise CommandError('Unknown type of DNS record %s' % rec_type)
173     return record_type
174
175
176 def dns_client_version(cli_version):
177     version = cli_version.upper()
178     if version == 'W2K':
179         client_version = dnsserver.DNS_CLIENT_VERSION_W2K
180     elif version == 'DOTNET':
181         client_version = dnsserver.DNS_CLIENT_VERSION_DOTNET
182     elif version == 'LONGHORN':
183         client_version = dnsserver.DNS_CLIENT_VERSION_LONGHORN
184     else:
185         raise CommandError('Unknown client version %s' % cli_version)
186     return client_version
187
188
189 def print_serverinfo(outf, typeid, serverinfo):
190     outf.write('  dwVersion                   : 0x%x\n' % serverinfo.dwVersion)
191     outf.write('  fBootMethod                 : %s\n' % boot_method_string(serverinfo.fBootMethod))
192     outf.write('  fAdminConfigured            : %s\n' % bool_string(serverinfo.fAdminConfigured))
193     outf.write('  fAllowUpdate                : %s\n' % bool_string(serverinfo.fAllowUpdate))
194     outf.write('  fDsAvailable                : %s\n' % bool_string(serverinfo.fDsAvailable))
195     outf.write('  pszServerName               : %s\n' % serverinfo.pszServerName)
196     outf.write('  pszDsContainer              : %s\n' % serverinfo.pszDsContainer)
197
198     if typeid != dnsserver.DNSSRV_TYPEID_SERVER_INFO:
199         outf.write('  aipServerAddrs              : %s\n' %
200                     ip4_array_string(serverinfo.aipServerAddrs))
201         outf.write('  aipListenAddrs              : %s\n' %
202                     ip4_array_string(serverinfo.aipListenAddrs))
203         outf.write('  aipForwarders               : %s\n' %
204                     ip4_array_string(serverinfo.aipForwarders))
205     else:
206         outf.write('  aipServerAddrs              : %s\n' %
207                     dns_addr_array_string(serverinfo.aipServerAddrs))
208         outf.write('  aipListenAddrs              : %s\n' %
209                     dns_addr_array_string(serverinfo.aipListenAddrs))
210         outf.write('  aipForwarders               : %s\n' %
211                     dns_addr_array_string(serverinfo.aipForwarders))
212
213     outf.write('  dwLogLevel                  : %d\n' % serverinfo.dwLogLevel)
214     outf.write('  dwDebugLevel                : %d\n' % serverinfo.dwDebugLevel)
215     outf.write('  dwForwardTimeout            : %d\n' % serverinfo.dwForwardTimeout)
216     outf.write('  dwRpcPrototol               : 0x%x\n' % serverinfo.dwRpcProtocol)
217     outf.write('  dwNameCheckFlag             : %s\n' % name_check_flag_string(serverinfo.dwNameCheckFlag))
218     outf.write('  cAddressAnswerLimit         : %d\n' % serverinfo.cAddressAnswerLimit)
219     outf.write('  dwRecursionRetry            : %d\n' % serverinfo.dwRecursionRetry)
220     outf.write('  dwRecursionTimeout          : %d\n' % serverinfo.dwRecursionTimeout)
221     outf.write('  dwMaxCacheTtl               : %d\n' % serverinfo.dwMaxCacheTtl)
222     outf.write('  dwDsPollingInterval         : %d\n' % serverinfo.dwDsPollingInterval)
223     outf.write('  dwScavengingInterval        : %d\n' % serverinfo.dwScavengingInterval)
224     outf.write('  dwDefaultRefreshInterval    : %d\n' % serverinfo.dwDefaultRefreshInterval)
225     outf.write('  dwDefaultNoRefreshInterval  : %d\n' % serverinfo.dwDefaultNoRefreshInterval)
226     outf.write('  fAutoReverseZones           : %s\n' % bool_string(serverinfo.fAutoReverseZones))
227     outf.write('  fAutoCacheUpdate            : %s\n' % bool_string(serverinfo.fAutoCacheUpdate))
228     outf.write('  fRecurseAfterForwarding     : %s\n' % bool_string(serverinfo.fRecurseAfterForwarding))
229     outf.write('  fForwardDelegations         : %s\n' % bool_string(serverinfo.fForwardDelegations))
230     outf.write('  fNoRecursion                : %s\n' % bool_string(serverinfo.fNoRecursion))
231     outf.write('  fSecureResponses            : %s\n' % bool_string(serverinfo.fSecureResponses))
232     outf.write('  fRoundRobin                 : %s\n' % bool_string(serverinfo.fRoundRobin))
233     outf.write('  fLocalNetPriority           : %s\n' % bool_string(serverinfo.fLocalNetPriority))
234     outf.write('  fBindSecondaries            : %s\n' % bool_string(serverinfo.fBindSecondaries))
235     outf.write('  fWriteAuthorityNs           : %s\n' % bool_string(serverinfo.fWriteAuthorityNs))
236     outf.write('  fStrictFileParsing          : %s\n' % bool_string(serverinfo.fStrictFileParsing))
237     outf.write('  fLooseWildcarding           : %s\n' % bool_string(serverinfo.fLooseWildcarding))
238     outf.write('  fDefaultAgingState          : %s\n' % bool_string(serverinfo.fDefaultAgingState))
239
240     if typeid != dnsserver.DNSSRV_TYPEID_SERVER_INFO_W2K:
241         outf.write('  dwRpcStructureVersion       : 0x%x\n' % serverinfo.dwRpcStructureVersion)
242         outf.write('  aipLogFilter                : %s\n' % dns_addr_array_string(serverinfo.aipLogFilter))
243         outf.write('  pwszLogFilePath             : %s\n' % serverinfo.pwszLogFilePath)
244         outf.write('  pszDomainName               : %s\n' % serverinfo.pszDomainName)
245         outf.write('  pszForestName               : %s\n' % serverinfo.pszForestName)
246         outf.write('  pszDomainDirectoryPartition : %s\n' % serverinfo.pszDomainDirectoryPartition)
247         outf.write('  pszForestDirectoryPartition : %s\n' % serverinfo.pszForestDirectoryPartition)
248
249         outf.write('  dwLocalNetPriorityNetMask   : 0x%x\n' % serverinfo.dwLocalNetPriorityNetMask)
250         outf.write('  dwLastScavengeTime          : %d\n' % serverinfo.dwLastScavengeTime)
251         outf.write('  dwEventLogLevel             : %d\n' % serverinfo.dwEventLogLevel)
252         outf.write('  dwLogFileMaxSize            : %d\n' % serverinfo.dwLogFileMaxSize)
253         outf.write('  dwDsForestVersion           : %d\n' % serverinfo.dwDsForestVersion)
254         outf.write('  dwDsDomainVersion           : %d\n' % serverinfo.dwDsDomainVersion)
255         outf.write('  dwDsDsaVersion              : %d\n' % serverinfo.dwDsDsaVersion)
256
257     if typeid == dnsserver.DNSSRV_TYPEID_SERVER_INFO:
258         outf.write('  fReadOnlyDC                 : %s\n' % bool_string(serverinfo.fReadOnlyDC))
259
260
261 def print_zoneinfo(outf, typeid, zoneinfo):
262     outf.write('  pszZoneName                 : %s\n' % zoneinfo.pszZoneName)
263     outf.write('  dwZoneType                  : %s\n' % zone_type_string(zoneinfo.dwZoneType))
264     outf.write('  fReverse                    : %s\n' % bool_string(zoneinfo.fReverse))
265     outf.write('  fAllowUpdate                : %s\n' % zone_update_string(zoneinfo.fAllowUpdate))
266     outf.write('  fPaused                     : %s\n' % bool_string(zoneinfo.fPaused))
267     outf.write('  fShutdown                   : %s\n' % bool_string(zoneinfo.fShutdown))
268     outf.write('  fAutoCreated                : %s\n' % bool_string(zoneinfo.fAutoCreated))
269     outf.write('  fUseDatabase                : %s\n' % bool_string(zoneinfo.fUseDatabase))
270     outf.write('  pszDataFile                 : %s\n' % zoneinfo.pszDataFile)
271     if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO:
272         outf.write('  aipMasters                  : %s\n' %
273                     ip4_array_string(zoneinfo.aipMasters))
274     else:
275         outf.write('  aipMasters                  : %s\n' %
276                     dns_addr_array_string(zoneinfo.aipMasters))
277     outf.write('  fSecureSecondaries          : %s\n' % zone_secondary_security_string(zoneinfo.fSecureSecondaries))
278     outf.write('  fNotifyLevel                : %s\n' % zone_notify_level_string(zoneinfo.fNotifyLevel))
279     if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO:
280         outf.write('  aipSecondaries              : %s\n' %
281                     ip4_array_string(zoneinfo.aipSecondaries))
282         outf.write('  aipNotify                   : %s\n' %
283                     ip4_array_string(zoneinfo.aipNotify))
284     else:
285         outf.write('  aipSecondaries              : %s\n' %
286                     dns_addr_array_string(zoneinfo.aipSecondaries))
287         outf.write('  aipNotify                   : %s\n' %
288                     dns_addr_array_string(zoneinfo.aipNotify))
289     outf.write('  fUseWins                    : %s\n' % bool_string(zoneinfo.fUseWins))
290     outf.write('  fUseNbstat                  : %s\n' % bool_string(zoneinfo.fUseNbstat))
291     outf.write('  fAging                      : %s\n' % bool_string(zoneinfo.fAging))
292     outf.write('  dwNoRefreshInterval         : %d\n' % zoneinfo.dwNoRefreshInterval)
293     outf.write('  dwRefreshInterval           : %d\n' % zoneinfo.dwRefreshInterval)
294     outf.write('  dwAvailForScavengeTime      : %d\n' % zoneinfo.dwAvailForScavengeTime)
295     if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO:
296         outf.write('  aipScavengeServers          : %s\n' %
297                     ip4_array_string(zoneinfo.aipScavengeServers))
298     else:
299         outf.write('  aipScavengeServers          : %s\n' %
300                     dns_addr_array_string(zoneinfo.aipScavengeServers))
301
302     if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO_W2K:
303         outf.write('  dwRpcStructureVersion       : 0x%x\n' % zoneinfo.dwRpcStructureVersion)
304         outf.write('  dwForwarderTimeout          : %d\n' % zoneinfo.dwForwarderTimeout)
305         outf.write('  fForwarderSlave             : %d\n' % zoneinfo.fForwarderSlave)
306         if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO:
307             outf.write('  aipLocalMasters             : %s\n' %
308                         ip4_array_string(zoneinfo.aipLocalMasters))
309         else:
310             outf.write('  aipLocalMasters             : %s\n' %
311                         dns_addr_array_string(zoneinfo.aipLocalMasters))
312         outf.write('  dwDpFlags                   : %s\n' % dp_flags_string(zoneinfo.dwDpFlags))
313         outf.write('  pszDpFqdn                   : %s\n' % zoneinfo.pszDpFqdn)
314         outf.write('  pwszZoneDn                  : %s\n' % zoneinfo.pwszZoneDn)
315         outf.write('  dwLastSuccessfulSoaCheck    : %d\n' % zoneinfo.dwLastSuccessfulSoaCheck)
316         outf.write('  dwLastSuccessfulXfr         : %d\n' % zoneinfo.dwLastSuccessfulXfr)
317
318     if typeid == dnsserver.DNSSRV_TYPEID_ZONE_INFO:
319         outf.write('  fQueuedForBackgroundLoad    : %s\n' % bool_string(zoneinfo.fQueuedForBackgroundLoad))
320         outf.write('  fBackgroundLoadInProgress   : %s\n' % bool_string(zoneinfo.fBackgroundLoadInProgress))
321         outf.write('  fReadOnlyZone               : %s\n' % bool_string(zoneinfo.fReadOnlyZone))
322         outf.write('  dwLastXfrAttempt            : %d\n' % zoneinfo.dwLastXfrAttempt)
323         outf.write('  dwLastXfrResult             : %d\n' % zoneinfo.dwLastXfrResult)
324
325
326 def print_zone(outf, typeid, zone):
327     outf.write('  pszZoneName                 : %s\n' % zone.pszZoneName)
328     outf.write('  Flags                       : %s\n' % zone_flags_string(zone.Flags))
329     outf.write('  ZoneType                    : %s\n' % zone_type_string(zone.ZoneType))
330     outf.write('  Version                     : %s\n' % zone.Version)
331
332     if typeid != dnsserver.DNSSRV_TYPEID_ZONE_W2K:
333         outf.write('  dwDpFlags                   : %s\n' % dp_flags_string(zone.dwDpFlags))
334         outf.write('  pszDpFqdn                   : %s\n' % zone.pszDpFqdn)
335
336
337 def print_enumzones(outf, typeid, zones):
338     outf.write('  %d zone(s) found\n' % zones.dwZoneCount)
339     for zone in zones.ZoneArray:
340         outf.write('\n')
341         print_zone(outf, typeid, zone)
342
343
344 def print_dns_record(outf, rec):
345     if rec.wType == dnsp.DNS_TYPE_A:
346         mesg = 'A: %s' % (rec.data)
347     elif rec.wType == dnsp.DNS_TYPE_AAAA:
348         mesg = 'AAAA: %s' % (rec.data)
349     elif rec.wType == dnsp.DNS_TYPE_PTR:
350         mesg = 'PTR: %s' % (rec.data.str)
351     elif rec.wType == dnsp.DNS_TYPE_NS:
352         mesg = 'NS: %s' % (rec.data.str)
353     elif rec.wType == dnsp.DNS_TYPE_CNAME:
354         mesg = 'CNAME: %s' % (rec.data.str)
355     elif rec.wType == dnsp.DNS_TYPE_SOA:
356         mesg = 'SOA: serial=%d, refresh=%d, retry=%d, expire=%d, ns=%s, email=%s' % (
357                     rec.data.dwSerialNo,
358                     rec.data.dwRefresh,
359                     rec.data.dwRetry,
360                     rec.data.dwExpire,
361                     rec.data.NamePrimaryServer.str,
362                     rec.data.ZoneAdministratorEmail.str)
363     elif rec.wType == dnsp.DNS_TYPE_MX:
364         mesg = 'MX: %s (%d)' % (rec.data.nameExchange.str, rec.data.wPreference)
365     elif rec.wType == dnsp.DNS_TYPE_SRV:
366         mesg = 'SRV: %s (%d, %d, %d)' % (rec.data.nameTarget.str, rec.data.wPort,
367                                          rec.data.wPriority, rec.data.wWeight)
368     elif rec.wType == dnsp.DNS_TYPE_TXT:
369         slist = ['"%s"' % name.str for name in rec.data.str]
370         mesg = 'TXT: %s' % ','.join(slist)
371     else:
372         mesg = 'Unknown: '
373     outf.write('    %s (flags=%x, serial=%d, ttl=%d)\n' % (
374                 mesg, rec.dwFlags, rec.dwSerial, rec.dwTtlSeconds))
375
376
377 def print_dnsrecords(outf, records):
378     for rec in records.rec:
379         outf.write('  Name=%s, Records=%d, Children=%d\n' % (
380                     rec.dnsNodeName.str,
381                     rec.wRecordCount,
382                     rec.dwChildCount))
383         for dns_rec in rec.records:
384                 print_dns_record(outf, dns_rec)
385
386
387 #
388 # Always create a copy of strings when creating DNS_RPC_RECORDs
389 # to overcome the bug in pidl generated python bindings.
390 #
391
392 class ARecord(dnsserver.DNS_RPC_RECORD):
393     def __init__(self, ip_addr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
394                     node_flag=0):
395         super(ARecord, self).__init__()
396         self.wType = dnsp.DNS_TYPE_A
397         self.dwFlags = rank | node_flag
398         self.dwSerial = serial
399         self.dwTtlSeconds = ttl
400         self._ip_addr = ip_addr[:]
401         self.data = self._ip_addr
402
403
404 class AAAARecord(dnsserver.DNS_RPC_RECORD):
405
406     def __init__(self, ip6_addr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
407                     node_flag=0):
408         super(AAAARecord, self).__init__()
409         self.wType = dnsp.DNS_TYPE_AAAA
410         self.dwFlags = rank | node_flag
411         self.dwSerial = serial
412         self.dwTtlSeconds = ttl
413         self._ip6_addr = ip6_addr[:]
414         self.data = self._ip6_addr
415
416
417 class PTRRecord(dnsserver.DNS_RPC_RECORD):
418
419     def __init__(self, ptr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
420                  node_flag=0):
421         super(PTRRecord, self).__init__()
422         self.wType = dnsp.DNS_TYPE_PTR
423         self.dwFlags = rank | node_flag
424         self.dwSerial = serial
425         self.dwTtleSeconds = ttl
426         self._ptr = ptr[:]
427         ptr_name = dnsserver.DNS_RPC_NAME()
428         ptr_name.str = self._ptr
429         ptr_name.len = len(ptr)
430         self.data = ptr_name
431
432
433 class CNameRecord(dnsserver.DNS_RPC_RECORD):
434
435     def __init__(self, cname, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
436                     node_flag=0):
437         super(CNameRecord, self).__init__()
438         self.wType = dnsp.DNS_TYPE_CNAME
439         self.dwFlags = rank | node_flag
440         self.dwSerial = serial
441         self.dwTtlSeconds = ttl
442         self._cname = cname[:]
443         cname_name = dnsserver.DNS_RPC_NAME()
444         cname_name.str = self._cname
445         cname_name.len = len(cname)
446         self.data = cname_name
447
448
449 class NSRecord(dnsserver.DNS_RPC_RECORD):
450
451     def __init__(self, dns_server, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
452                     node_flag=0):
453         super(NSRecord, self).__init__()
454         self.wType = dnsp.DNS_TYPE_NS
455         self.dwFlags = rank | node_flag
456         self.dwSerial = serial
457         self.dwTtlSeconds = ttl
458         self._dns_server = dns_server[:]
459         ns = dnsserver.DNS_RPC_NAME()
460         ns.str = self._dns_server
461         ns.len = len(dns_server)
462         self.data = ns
463
464
465 class MXRecord(dnsserver.DNS_RPC_RECORD):
466
467     def __init__(self, mail_server, preference, serial=1, ttl=900,
468                  rank=dnsp.DNS_RANK_ZONE, node_flag=0):
469         super(MXRecord, self).__init__()
470         self.wType = dnsp.DNS_TYPE_MX
471         self.dwFlags = rank | node_flag
472         self.dwSerial = serial
473         self.dwTtlSeconds = ttl
474         self._mail_server = mail_server[:]
475         mx = dnsserver.DNS_RPC_RECORD_NAME_PREFERENCE()
476         mx.wPreference = preference
477         mx.nameExchange.str = self._mail_server
478         mx.nameExchange.len = len(mail_server)
479         self.data = mx
480
481
482 class SOARecord(dnsserver.DNS_RPC_RECORD):
483
484     def __init__(self, mname, rname, serial=1, refresh=900, retry=600,
485                  expire=86400, minimum=3600, ttl=3600, rank=dnsp.DNS_RANK_ZONE,
486                  node_flag=dnsp.DNS_RPC_FLAG_AUTH_ZONE_ROOT):
487         super(SOARecord, self).__init__()
488         self.wType = dnsp.DNS_TYPE_SOA
489         self.dwFlags = rank | node_flag
490         self.dwSerial = serial
491         self.dwTtlSeconds = ttl
492         self._mname = mname[:]
493         self._rname = rname[:]
494         soa = dnsserver.DNS_RPC_RECORD_SOA()
495         soa.dwSerialNo = serial
496         soa.dwRefresh = refresh
497         soa.dwRetry = retry
498         soa.dwExpire = expire
499         soa.NamePrimaryServer.str = self._mname
500         soa.NamePrimaryServer.len = len(mname)
501         soa.ZoneAdministratorEmail.str = self._rname
502         soa.ZoneAdministratorEmail.len = len(rname)
503         self.data = soa
504
505
506 class SRVRecord(dnsserver.DNS_RPC_RECORD):
507
508     def __init__(self, target, port, priority=0, weight=100, serial=1, ttl=900,
509                 rank=dnsp.DNS_RANK_ZONE, node_flag=0):
510         super(SRVRecord, self).__init__()
511         self.wType = dnsp.DNS_TYPE_SRV
512         self.dwFlags = rank | node_flag
513         self.dwSerial = serial
514         self.dwTtlSeconds = ttl
515         self._target = target[:]
516         srv = dnsserver.DNS_RPC_RECORD_SRV()
517         srv.wPriority = priority
518         srv.wWeight = weight
519         srv.wPort = port
520         srv.nameTarget.str = self._target
521         srv.nameTarget.len = len(target)
522         self.data = srv
523
524
525 class TXTRecord(dnsserver.DNS_RPC_RECORD):
526
527     def __init__(self, slist, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
528                 node_flag=0):
529         super(TXTRecord, self).__init__()
530         self.wType = dnsp.DNS_TYPE_TXT
531         self.dwFlags = rank | node_flag
532         self.dwSerial = serial
533         self.dwTtlSeconds = ttl
534         self._slist = []
535         for s in slist:
536             self._slist.append(s[:])
537         names = []
538         for s in self._slist:
539             name = dnsserver.DNS_RPC_NAME()
540             name.str = s
541             name.len = len(s)
542             names.append(name)
543         txt = dnsserver.DNS_RPC_RECORD_STRING()
544         txt.count = len(slist)
545         txt.str = names
546         self.data = txt
547
548
549 # Convert data into a dns record
550 def data_to_dns_record(record_type, data):
551     if record_type == dnsp.DNS_TYPE_A:
552         rec = ARecord(data)
553     elif record_type == dnsp.DNS_TYPE_AAAA:
554         rec = AAAARecord(data)
555     elif record_type == dnsp.DNS_TYPE_PTR:
556         rec = PTRRecord(data)
557     elif record_type == dnsp.DNS_TYPE_CNAME:
558         rec = CNameRecord(data)
559     elif record_type == dnsp.DNS_TYPE_NS:
560         rec = NSRecord(data)
561     elif record_type == dnsp.DNS_TYPE_MX:
562         tmp = data.split(' ')
563         if len(tmp) != 2:
564             raise CommandError('Data requires 2 elements - mail_server, preference')
565         mail_server = tmp[0]
566         preference = int(tmp[1])
567         rec = MXRecord(mail_server, preference)
568     elif record_type == dnsp.DNS_TYPE_SRV:
569         tmp = data.split(' ')
570         if len(tmp) != 4:
571             raise CommandError('Data requires 4 elements - server, port, priority, weight')
572         server = tmp[0]
573         port = int(tmp[1])
574         priority = int(tmp[2])
575         weight = int(tmp[3])
576         rec = SRVRecord(server, port, priority=priority, weight=weight)
577     elif record_type == dnsp.DNS_TYPE_SOA:
578         tmp = data.split(' ')
579         if len(tmp) != 7:
580             raise CommandError('Data requires 7 elements - nameserver, email, serial, '
581                                'refresh, retry, expire, minimumttl')
582         nameserver = tmp[0]
583         email = tmp[1]
584         serial = int(tmp[2])
585         refresh = int(tmp[3])
586         retry = int(tmp[4])
587         expire = int(tmp[5])
588         minimum = int(tmp[6])
589         rec = SOARecord(nameserver, email, serial=serial, refresh=refresh,
590                         retry=retry, expire=expire, minimum=minimum)
591     elif record_type == dnsp.DNS_TYPE_TXT:
592         slist = shlex.split(data)
593         rec = TXTRecord(slist)
594     else:
595         raise CommandError('Unsupported record type')
596     return rec
597
598
599 # Match dns name (of type DNS_RPC_NAME)
600 def dns_name_equal(n1, n2):
601     return n1.str.rstrip('.').lower() == n2.str.rstrip('.').lower()
602
603
604 # Match a dns record with specified data
605 def dns_record_match(dns_conn, server, zone, name, record_type, data):
606     urec = data_to_dns_record(record_type, data)
607
608     select_flags = dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
609
610     try:
611         buflen, res = dns_conn.DnssrvEnumRecords2(
612             dnsserver.DNS_CLIENT_VERSION_LONGHORN, 0, server, zone, name, None,
613             record_type, select_flags, None, None)
614     except RuntimeError, e:
615         return None
616
617     if not res or res.count == 0:
618         return None
619
620     rec_match = None
621     for rec in res.rec[0].records:
622         if rec.wType != record_type:
623             continue
624
625         found = False
626         if record_type == dnsp.DNS_TYPE_A:
627             if rec.data == urec.data:
628                 found = True
629         elif record_type == dnsp.DNS_TYPE_AAAA:
630             if rec.data == urec.data:
631                 found = True
632         elif record_type == dnsp.DNS_TYPE_PTR:
633             if dns_name_equal(rec.data, urec.data):
634                 found = True
635         elif record_type == dnsp.DNS_TYPE_CNAME:
636             if dns_name_equal(rec.data, urec.data):
637                 found = True
638         elif record_type == dnsp.DNS_TYPE_NS:
639             if dns_name_equal(rec.data, urec.data):
640                 found = True
641         elif record_type == dnsp.DNS_TYPE_MX:
642             if dns_name_equal(rec.data.nameExchange, urec.data.nameExchange) and \
643                rec.data.wPreference == urec.data.wPreference:
644                 found = True
645         elif record_type == dnsp.DNS_TYPE_SRV:
646             if rec.data.wPriority == urec.data.wPriority and \
647                rec.data.wWeight == urec.data.wWeight and \
648                rec.data.wPort == urec.data.wPort and \
649                dns_name_equal(rec.data.nameTarget, urec.data.nameTarget):
650                 found = True
651         elif record_type == dnsp.DNS_TYPE_SOA:
652             if rec.data.dwSerialNo == urec.data.dwSerialNo and \
653                rec.data.dwRefresh == urec.data.dwRefresh and \
654                rec.data.dwRetry == urec.data.dwRetry and \
655                rec.data.dwExpire == urec.data.dwExpire and \
656                rec.data.dwMinimumTtl == urec.data.dwMinimumTtl and \
657                dns_name_equal(rec.data.NamePrimaryServer,
658                               urec.data.NamePrimaryServer) and \
659                dns_name_equal(rec.data.ZoneAdministratorEmail,
660                               urec.data.ZoneAdministratorEmail):
661                 found = True
662         elif record_type == dnsp.DNS_TYPE_TXT:
663             if rec.data.count == urec.data.count:
664                 found = True
665                 for i in xrange(rec.data.count):
666                     found = found and \
667                             (rec.data.str[i].str == urec.data.str[i].str)
668
669         if found:
670             rec_match = rec
671             break
672
673     return rec_match
674
675
676 class cmd_serverinfo(Command):
677     """Query for Server information"""
678
679     synopsis = '%prog <server> [options]'
680
681     takes_args = [ 'server' ]
682
683     takes_optiongroups = {
684         "sambaopts": options.SambaOptions,
685         "versionopts": options.VersionOptions,
686         "credopts": options.CredentialsOptions,
687     }
688
689     takes_options = [
690         Option('--client-version', help='Client Version',
691                 default='longhorn', metavar='w2k|dotnet|longhorn',
692                 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
693     ]
694
695     def run(self, server, cli_ver, sambaopts=None, credopts=None,
696             versionopts=None):
697         self.lp = sambaopts.get_loadparm()
698         self.creds = credopts.get_credentials(self.lp)
699         dns_conn = dns_connect(server, self.lp, self.creds)
700
701         client_version = dns_client_version(cli_ver)
702
703         typeid, res = dns_conn.DnssrvQuery2(client_version, 0, server,
704                                             None, 'ServerInfo')
705         print_serverinfo(self.outf, typeid, res)
706
707
708 class cmd_zoneinfo(Command):
709     """Query for zone information"""
710
711     synopsis = '%prog <server> <zone> [options]'
712
713     takes_args = [ 'server', 'zone' ]
714
715     takes_optiongroups = {
716         "sambaopts": options.SambaOptions,
717         "versionopts": options.VersionOptions,
718         "credopts": options.CredentialsOptions,
719     }
720
721     takes_options = [
722         Option('--client-version', help='Client Version',
723                 default='longhorn', metavar='w2k|dotnet|longhorn',
724                 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
725     ]
726
727     def run(self, server, zone, cli_ver, sambaopts=None, credopts=None,
728             versionopts=None):
729         self.lp = sambaopts.get_loadparm()
730         self.creds = credopts.get_credentials(self.lp)
731         dns_conn = dns_connect(server, self.lp, self.creds)
732
733         client_version = dns_client_version(cli_ver)
734
735         typeid, res = dns_conn.DnssrvQuery2(client_version, 0, server, zone,
736                                             'ZoneInfo')
737         print_zoneinfo(self.outf, typeid, res)
738
739
740 class cmd_zonelist(Command):
741     """Query for zones"""
742
743     synopsis = '%prog <server> [options]'
744
745     takes_args = [ 'server' ]
746
747     takes_optiongroups = {
748         "sambaopts": options.SambaOptions,
749         "versionopts": options.VersionOptions,
750         "credopts": options.CredentialsOptions,
751     }
752
753     takes_options = [
754         Option('--client-version', help='Client Version',
755                 default='longhorn', metavar='w2k|dotnet|longhorn',
756                 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
757         Option('--primary', help='List primary zones (default)',
758                 action='store_true', dest='primary'),
759         Option('--secondary', help='List secondary zones',
760                 action='store_true', dest='secondary'),
761         Option('--cache', help='List cached zones',
762                 action='store_true', dest='cache'),
763         Option('--auto', help='List automatically created zones',
764                 action='store_true', dest='auto'),
765         Option('--forward', help='List forward zones',
766                 action='store_true', dest='forward'),
767         Option('--reverse', help='List reverse zones',
768                 action='store_true', dest='reverse'),
769         Option('--ds', help='List directory integrated zones',
770                 action='store_true', dest='ds'),
771         Option('--non-ds', help='List non-directory zones',
772                 action='store_true', dest='nonds')
773     ]
774
775     def run(self, server, cli_ver, primary=False, secondary=False, cache=False,
776                 auto=False, forward=False, reverse=False, ds=False, nonds=False,
777                 sambaopts=None, credopts=None, versionopts=None):
778         request_filter = 0
779
780         if primary:
781             request_filter |= dnsserver.DNS_ZONE_REQUEST_PRIMARY
782         if secondary:
783             request_filter |= dnsserver.DNS_ZONE_REQUEST_SECONDARY
784         if cache:
785             request_filter |= dnsserver.DNS_ZONE_REQUEST_CACHE
786         if auto:
787             request_filter |= dnsserver.DNS_ZONE_REQUEST_AUTO
788         if forward:
789             request_filter |= dnsserver.DNS_ZONE_REQUEST_FORWARD
790         if reverse:
791             request_filter |= dnsserver.DNS_ZONE_REQUEST_REVERSE
792         if ds:
793             request_filter |= dnsserver.DNS_ZONE_REQUEST_DS
794         if nonds:
795             request_filter |= dnsserver.DNS_ZONE_REQUEST_NON_DS
796
797         if request_filter == 0:
798             request_filter = dnsserver.DNS_ZONE_REQUEST_PRIMARY
799
800         self.lp = sambaopts.get_loadparm()
801         self.creds = credopts.get_credentials(self.lp)
802         dns_conn = dns_connect(server, self.lp, self.creds)
803
804         client_version = dns_client_version(cli_ver)
805
806         typeid, res = dns_conn.DnssrvComplexOperation2(client_version,
807                                                         0, server, None,
808                                                         'EnumZones',
809                                                         dnsserver.DNSSRV_TYPEID_DWORD,
810                                                         request_filter)
811
812         if client_version == dnsserver.DNS_CLIENT_VERSION_W2K:
813             typeid = dnsserver.DNSSRV_TYPEID_ZONE_W2K
814         else:
815             typeid = dnsserver.DNSSRV_TYPEID_ZONE
816         print_enumzones(self.outf, typeid, res)
817
818
819 class cmd_zonecreate(Command):
820     """Create a zone"""
821
822     synopsis = '%prog <server> <zone> [options]'
823
824     takes_args = [ 'server', 'zone' ]
825
826     takes_optiongroups = {
827         "sambaopts": options.SambaOptions,
828         "versionopts": options.VersionOptions,
829         "credopts": options.CredentialsOptions,
830     }
831
832     takes_options = [
833         Option('--client-version', help='Client Version',
834                 default='longhorn', metavar='w2k|dotnet|longhorn',
835                 choices=['w2k','dotnet','longhorn'], dest='cli_ver')
836     ]
837
838     def run(self, server, zone, cli_ver, sambaopts=None, credopts=None,
839             versionopts=None):
840
841         self.lp = sambaopts.get_loadparm()
842         self.creds = credopts.get_credentials(self.lp)
843         dns_conn = dns_connect(server, self.lp, self.creds)
844
845         zone = zone.lower()
846
847         client_version = dns_client_version(cli_ver)
848         if client_version == dnsserver.DNS_CLIENT_VERSION_W2K:
849             typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE_W2K
850             zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_W2K()
851             zone_create_info.pszZoneName = zone
852             zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
853             zone_create_info.fAllowUpdate = dnsp.DNS_ZONE_UPDATE_SECURE
854             zone_create_info.fAging = 0
855         elif client_version == dnsserver.DNS_CLIENT_VERSION_DOTNET:
856             typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE_DOTNET
857             zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_DOTNET()
858             zone_create_info.pszZoneName = zone
859             zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
860             zone_create_info.fAllowUpdate = dnsp.DNS_ZONE_UPDATE_SECURE
861             zone_create_info.fAging = 0
862             zone_create_info.dwDpFlags = dnsserver.DNS_DP_DOMAIN_DEFAULT
863         else:
864             typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE
865             zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_LONGHORN()
866             zone_create_info.pszZoneName = zone
867             zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
868             zone_create_info.fAllowUpdate = dnsp.DNS_ZONE_UPDATE_SECURE
869             zone_create_info.fAging = 0
870             zone_create_info.dwDpFlags = dnsserver.DNS_DP_DOMAIN_DEFAULT
871
872         res = dns_conn.DnssrvOperation2(client_version, 0, server, None,
873                                         0, 'ZoneCreate', typeid,
874                                         zone_create_info)
875         self.outf.write('Zone %s created successfully\n' % zone)
876
877
878 class cmd_zonedelete(Command):
879     """Delete a zone"""
880
881     synopsis = '%prog <server> <zone> [options]'
882
883     takes_args = [ 'server', 'zone' ]
884
885     takes_optiongroups = {
886         "sambaopts": options.SambaOptions,
887         "versionopts": options.VersionOptions,
888         "credopts": options.CredentialsOptions,
889     }
890
891     def run(self, server, zone, sambaopts=None, credopts=None,
892             versionopts=None):
893
894         self.lp = sambaopts.get_loadparm()
895         self.creds = credopts.get_credentials(self.lp)
896         dns_conn = dns_connect(server, self.lp, self.creds)
897
898         zone = zone.lower()
899         res = dns_conn.DnssrvOperation2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
900                                         0, server, zone, 0, 'DeleteZoneFromDs',
901                                         dnsserver.DNSSRV_TYPEID_NULL,
902                                         None)
903         self.outf.write('Zone %s delete successfully\n' % zone)
904
905
906 class cmd_query(Command):
907     """Query a name."""
908
909     synopsis = '%prog <server> <zone> <name> <A|AAAA|CNAME|MX|NS|SOA|SRV|TXT|ALL> [options]'
910
911     takes_args = [ 'server', 'zone', 'name', 'rtype' ]
912
913     takes_optiongroups = {
914         "sambaopts": options.SambaOptions,
915         "versionopts": options.VersionOptions,
916         "credopts": options.CredentialsOptions,
917     }
918
919     takes_options = [
920         Option('--authority', help='Search authoritative records (default)',
921                 action='store_true', dest='authority'),
922         Option('--cache', help='Search cached records',
923                 action='store_true', dest='cache'),
924         Option('--glue', help='Search glue records',
925                 action='store_true', dest='glue'),
926         Option('--root', help='Search root hints',
927                 action='store_true', dest='root'),
928         Option('--additional', help='List additional records',
929                 action='store_true', dest='additional'),
930         Option('--no-children', help='Do not list children',
931                 action='store_true', dest='no_children'),
932         Option('--only-children', help='List only children',
933                 action='store_true', dest='only_children')
934     ]
935
936     def run(self, server, zone, name, rtype, authority=False, cache=False,
937             glue=False, root=False, additional=False, no_children=False,
938             only_children=False, sambaopts=None, credopts=None,
939             versionopts=None):
940         record_type = dns_type_flag(rtype)
941
942         select_flags = 0
943         if authority:
944             select_flags |= dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
945         if cache:
946             select_flags |= dnsserver.DNS_RPC_VIEW_CACHE_DATA
947         if glue:
948             select_flags |= dnsserver.DNS_RPC_VIEW_GLUE_DATA
949         if root:
950             select_flags |= dnsserver.DNS_RPC_VIEW_ROOT_HINT_DATA
951         if additional:
952             select_flags |= dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA
953         if no_children:
954             select_flags |= dnsserver.DNS_RPC_VIEW_NO_CHILDREN
955         if only_children:
956             select_flags |= dnsserver.DNS_RPC_VIEW_ONLY_CHILDREN
957
958         if select_flags == 0:
959             select_flags = dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
960
961         if select_flags == dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA:
962             self.outf.write('Specify either --authority or --root along with --additional.\n')
963             self.outf.write('Assuming --authority.\n')
964             select_flags |= dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
965
966         self.lp = sambaopts.get_loadparm()
967         self.creds = credopts.get_credentials(self.lp)
968         dns_conn = dns_connect(server, self.lp, self.creds)
969
970         buflen, res = dns_conn.DnssrvEnumRecords2(
971                 dnsserver.DNS_CLIENT_VERSION_LONGHORN, 0, server, zone, name,
972                 None, record_type, select_flags, None, None)
973         print_dnsrecords(self.outf, res)
974
975
976 class cmd_roothints(Command):
977     """Query root hints"""
978
979     synopsis = '%prog <server> [<name>] [options]'
980
981     takes_args = [ 'server', 'name?' ]
982
983     takes_optiongroups = {
984         "sambaopts": options.SambaOptions,
985         "versionopts": options.VersionOptions,
986         "credopts": options.CredentialsOptions,
987     }
988
989     def run(self, server, name='.', sambaopts=None, credopts=None,
990             versionopts=None):
991         record_type = dnsp.DNS_TYPE_NS
992         select_flags = (dnsserver.DNS_RPC_VIEW_ROOT_HINT_DATA |
993                         dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA)
994
995         self.lp = sambaopts.get_loadparm()
996         self.creds = credopts.get_credentials(self.lp)
997         dns_conn = dns_connect(server, self.lp, self.creds)
998
999         buflen, res = dns_conn.DnssrvEnumRecords2(
1000             dnsserver.DNS_CLIENT_VERSION_LONGHORN, 0, server, '..RootHints',
1001             name, None, record_type, select_flags, None, None)
1002         print_dnsrecords(self.outf, res)
1003
1004
1005 class cmd_add_record(Command):
1006     """Add a DNS record
1007
1008        For each type data contents are as follows:
1009          A      ipv4_address_string
1010          AAAA   ipv6_address_string
1011          PTR    fqdn_string
1012          CNAME  fqdn_string
1013          NS     fqdn_string
1014          MX     "fqdn_string preference"
1015          SRV    "fqdn_string port priority weight"
1016          TXT    "'string1' 'string2' ..."
1017     """
1018
1019     synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS|MX|SRV|TXT> <data>'
1020
1021     takes_args = [ 'server', 'zone', 'name', 'rtype', 'data' ]
1022
1023     takes_optiongroups = {
1024         "sambaopts": options.SambaOptions,
1025         "versionopts": options.VersionOptions,
1026         "credopts": options.CredentialsOptions,
1027     }
1028
1029     def run(self, server, zone, name, rtype, data, sambaopts=None,
1030             credopts=None, versionopts=None):
1031
1032         if rtype.upper() not in ('A','AAAA','PTR','CNAME','NS','MX','SRV','TXT'):
1033             raise CommandError('Adding record of type %s is not supported' % rtype)
1034
1035         record_type = dns_type_flag(rtype)
1036         rec = data_to_dns_record(record_type, data)
1037
1038         self.lp = sambaopts.get_loadparm()
1039         self.creds = credopts.get_credentials(self.lp)
1040         dns_conn = dns_connect(server, self.lp, self.creds)
1041
1042         rec_match = dns_record_match(dns_conn, server, zone, name, record_type,
1043                 data)
1044         if rec_match is not None:
1045             raise CommandError('Record already exists')
1046
1047         add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
1048         add_rec_buf.rec = rec
1049
1050         dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
1051                                      0, server, zone, name, add_rec_buf, None)
1052         self.outf.write('Record added successfully\n')
1053
1054
1055 class cmd_update_record(Command):
1056     """Update a DNS record
1057
1058        For each type data contents are as follows:
1059          A      ipv4_address_string
1060          AAAA   ipv6_address_string
1061          PTR    fqdn_string
1062          CNAME  fqdn_string
1063          NS     fqdn_string
1064          MX     "fqdn_string preference"
1065          SRV    "fqdn_string port priority weight"
1066          TXT    "'string1' 'string2' ..."
1067     """
1068
1069     synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS|MX|SRV|TXT> <olddata> <newdata>'
1070
1071     takes_args = [ 'server', 'zone', 'name', 'rtype', 'olddata', 'newdata' ]
1072
1073     takes_optiongroups = {
1074         "sambaopts": options.SambaOptions,
1075         "versionopts": options.VersionOptions,
1076         "credopts": options.CredentialsOptions,
1077     }
1078
1079     def run(self, server, zone, name, rtype, olddata, newdata,
1080                 sambaopts=None, credopts=None, versionopts=None):
1081
1082         if rtype.upper() not in ('A','AAAA','PTR','CNAME','NS','MX','SRV','TXT'):
1083             raise CommandError('Updating record of type %s is not supported' % rtype)
1084
1085         record_type = dns_type_flag(rtype)
1086         rec = data_to_dns_record(record_type, newdata)
1087
1088         self.lp = sambaopts.get_loadparm()
1089         self.creds = credopts.get_credentials(self.lp)
1090         dns_conn = dns_connect(server, self.lp, self.creds)
1091
1092         rec_match = dns_record_match(dns_conn, server, zone, name, record_type,
1093                 olddata)
1094         if not rec_match:
1095             raise CommandError('Record does not exist')
1096
1097         # Copy properties from existing record to new record
1098         rec.dwFlags = rec_match.dwFlags
1099         rec.dwSerial = rec_match.dwSerial
1100         rec.dwTtlSeconds = rec_match.dwTtlSeconds
1101         rec.dwTimeStamp = rec_match.dwTimeStamp
1102
1103         add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
1104         add_rec_buf.rec = rec
1105
1106         del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
1107         del_rec_buf.rec = rec_match
1108
1109         dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
1110                                         0,
1111                                         server,
1112                                         zone,
1113                                         name,
1114                                         add_rec_buf,
1115                                         del_rec_buf)
1116         self.outf.write('Record updated succefully\n')
1117
1118
1119 class cmd_delete_record(Command):
1120     """Delete a DNS record
1121
1122        For each type data contents are as follows:
1123          A      ipv4_address_string
1124          AAAA   ipv6_address_string
1125          PTR    fqdn_string
1126          CNAME  fqdn_string
1127          NS     fqdn_string
1128          MX     "fqdn_string preference"
1129          SRV    "fqdn_string port priority weight"
1130          TXT    "'string1' 'string2' ..."
1131     """
1132
1133     synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS|MX|SRV|TXT> <data>'
1134
1135     takes_args = [ 'server', 'zone', 'name', 'rtype', 'data' ]
1136
1137     takes_optiongroups = {
1138         "sambaopts": options.SambaOptions,
1139         "versionopts": options.VersionOptions,
1140         "credopts": options.CredentialsOptions,
1141     }
1142
1143     def run(self, server, zone, name, rtype, data, sambaopts=None, credopts=None, versionopts=None):
1144
1145         if rtype.upper() not in ('A','AAAA','PTR','CNAME','NS','MX','SRV','TXT'):
1146             raise CommandError('Deleting record of type %s is not supported' % rtype)
1147
1148         record_type = dns_type_flag(rtype)
1149
1150         self.lp = sambaopts.get_loadparm()
1151         self.creds = credopts.get_credentials(self.lp)
1152         dns_conn = dns_connect(server, self.lp, self.creds)
1153
1154         rec_match = dns_record_match(dns_conn, server, zone, name, record_type, data)
1155         if not rec_match:
1156             raise CommandError('Record does not exist')
1157
1158         del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
1159         del_rec_buf.rec = rec_match
1160
1161         dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
1162                                         0,
1163                                         server,
1164                                         zone,
1165                                         name,
1166                                         None,
1167                                         del_rec_buf)
1168         self.outf.write('Record deleted succefully\n')
1169
1170
1171 class cmd_dns(SuperCommand):
1172     """Domain Name Service (DNS) management"""
1173
1174     subcommands = {}
1175     subcommands['serverinfo'] = cmd_serverinfo()
1176     subcommands['zoneinfo'] = cmd_zoneinfo()
1177     subcommands['zonelist'] = cmd_zonelist()
1178     subcommands['zonecreate'] = cmd_zonecreate()
1179     subcommands['zonedelete'] = cmd_zonedelete()
1180     subcommands['query'] = cmd_query()
1181     subcommands['roothints'] = cmd_roothints()
1182     subcommands['add'] = cmd_add_record()
1183     subcommands['update'] = cmd_update_record()
1184     subcommands['delete'] = cmd_delete_record()