ctdb-scripts: Improve update and listing code
[samba4-gss.git] / python / samba / netcmd / common.py
blob2aa50c754aa4b3c075f54e1244509e18ff1dfacb
1 # common functions for samba-tool python commands
3 # Copyright Andrew Tridgell 2010
4 # Copyright Giampaolo Lauria 2011 <lauria2@yahoo.com>
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 import re
21 from samba.dcerpc import nbt
22 from samba.net import Net
23 from samba.netcmd import CommandError
24 import ldb
27 # In MS AD, setting a timeout to '(never)' corresponds to this value
28 NEVER_TIMESTAMP = int(-0x8000000000000000)
31 def _get_user_realm_domain(user, sam=None):
32 r""" get the realm or the domain and the base user
33 from user like:
34 * username
35 * DOMAIN\username
36 * username@REALM
38 A SamDB object can also be passed in to check
39 our domain or realm against the obtained ones.
40 """
41 baseuser = user
42 m = re.match(r"(\w+)\\(\w+$)", user)
43 if m:
44 domain = m.group(1)
45 baseuser = m.group(2)
47 if sam is not None:
48 our_domain = sam.domain_netbios_name()
49 if domain.lower() != our_domain.lower():
50 raise CommandError(f"Given domain '{domain}' does not match "
51 f"our domain '{our_domain}'!")
53 return (baseuser.lower(), "", domain.upper())
55 realm = ""
56 m = re.match(r"(\w+)@(\w+)", user)
57 if m:
58 baseuser = m.group(1)
59 realm = m.group(2)
61 if sam is not None:
62 our_realm = sam.domain_dns_name()
63 our_realm_initial = our_realm.split('.', 1)[0]
64 if realm.lower() != our_realm_initial.lower():
65 raise CommandError(f"Given realm '{realm}' does not match our "
66 f"realm '{our_realm}'!")
68 return (baseuser.lower(), realm.upper(), "")
71 def netcmd_dnsname(lp):
72 """return the full DNS name of our own host. Used as a default
73 for hostname when running status queries"""
74 return lp.get('netbios name').lower() + "." + lp.get('realm').lower()
77 def netcmd_finddc(lp, creds, realm=None):
78 """Return domain-name of a writable/ldap-capable DC for the default
79 domain (parameter "realm" in smb.conf) unless another realm has been
80 specified as argument"""
81 net = Net(creds=creds, lp=lp)
82 if realm is None:
83 realm = lp.get('realm')
84 cldap_ret = net.finddc(domain=realm,
85 flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS | nbt.NBT_SERVER_WRITABLE)
86 return cldap_ret.pdc_dns_name
89 def netcmd_get_domain_infos_via_cldap(lp, creds, address=None):
90 """Return domain information (CLDAP record) of the ldap-capable
91 DC with the specified address"""
92 net = Net(creds=creds, lp=lp)
93 cldap_ret = net.finddc(address=address,
94 flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
95 return cldap_ret
97 def is_printable_attr_val(val):
98 import unicodedata
100 # The value must be convertible to a string value.
101 try:
102 str_val = str(val)
103 except:
104 return False
106 # Characters of the Unicode Character Category "C" ("Other") are
107 # supposed to be not printable. The category "C" includes control
108 # characters, format specifier and others.
109 for c in str_val:
110 if unicodedata.category(c)[0] == 'C':
111 return False
113 return True
115 def get_ldif_for_editor(samdb, msg):
117 # Copy the given message, because we do not
118 # want to modify the original message.
119 m = ldb.Message()
120 m.dn = msg.dn
122 for k in msg.keys():
123 if k == "dn":
124 continue
125 vals = msg[k]
126 m[k] = vals
127 need_base64 = False
128 for v in vals:
129 if is_printable_attr_val(v):
130 continue
131 need_base64 = True
132 break
133 if not need_base64:
134 m[k].set_flags(ldb.FLAG_FORCE_NO_BASE64_LDIF)
136 result_ldif = samdb.write_ldif(m, ldb.CHANGETYPE_NONE)
138 return result_ldif
141 def timestamp_to_mins(timestamp_str):
142 """Converts a timestamp in -100 nanosecond units to minutes"""
143 # treat a timestamp of 'never' the same as zero (this should work OK for
144 # most settings, and it displays better than trying to convert
145 # -0x8000000000000000 to minutes)
146 if int(timestamp_str) == NEVER_TIMESTAMP:
147 return 0
148 else:
149 return abs(int(timestamp_str)) / (1e7 * 60)
152 def timestamp_to_days(timestamp_str):
153 """Converts a timestamp in -100 nanosecond units to days"""
154 return timestamp_to_mins(timestamp_str) / (60 * 24)
157 def attr_default(msg, attrname, default):
158 """get an attribute from a ldap msg with a default"""
159 if attrname in msg:
160 return msg[attrname][0]
161 return default