samba-tool gpo: add helper method for tmpdir construction
[amitay/samba.git] / python / samba / ms_display_specifiers.py
1 # Create DisplaySpecifiers LDIF (as a string) from the documents provided by
2 # Microsoft under the WSPP.
3 #
4 # Copyright (C) Andrew Kroeger <andrew@id10ts.net> 2009
5 #
6 # Based on ms_schema.py
7 #
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 from __future__ import print_function
21
22 import re
23
24
25 def __read_folded_line(f, buffer):
26     """Read a line from an LDIF file, unfolding it"""
27     line = buffer
28
29     while True:
30         l = f.readline()
31
32         if l[:1] == " ":
33             # continued line
34
35             # cannot fold an empty line
36             assert(line != "" and line != "\n")
37
38             # preserves '\n '
39             line = line + l
40         else:
41             # non-continued line
42             if line == "":
43                 line = l
44
45                 if l == "":
46                     # eof, definitely won't be folded
47                     break
48             else:
49                 # marks end of a folded line
50                 # line contains the now unfolded line
51                 # buffer contains the start of the next possibly folded line
52                 buffer = l
53                 break
54
55     return (line, buffer)
56
57
58 # Only compile regexp once.
59 # Will not match options after the attribute type.
60 attr_type_re = re.compile("^([A-Za-z][A-Za-z0-9-]*):")
61
62
63 def __read_raw_entries(f):
64     """Read an LDIF entry, only unfolding lines"""
65
66     buffer = ""
67
68     while True:
69         entry = []
70
71         while True:
72             (l, buffer) = __read_folded_line(f, buffer)
73
74             if l[:1] == "#":
75                 continue
76
77             if l == "\n" or l == "":
78                 break
79
80             m = attr_type_re.match(l)
81
82             if m:
83                 if l[-1:] == "\n":
84                     l = l[:-1]
85
86                 entry.append(l)
87             else:
88                 print("Invalid line: %s" % l, end=' ', file=sys.stderr)
89                 sys.exit(1)
90
91         if len(entry):
92             yield entry
93
94         if l == "":
95             break
96
97
98 def fix_dn(dn):
99     """Fix a string DN to use ${CONFIGDN}"""
100
101     if dn.find("<Configuration NC Distinguished Name>") != -1:
102         dn = dn.replace("\n ", "")
103         return dn.replace("<Configuration NC Distinguished Name>", "${CONFIGDN}")
104     else:
105         return dn
106
107
108 def __write_ldif_one(entry):
109     """Write out entry as LDIF"""
110     out = []
111
112     for l in entry:
113         if l[2] == 0:
114             out.append("%s: %s" % (l[0], l[1]))
115         else:
116             # This is a base64-encoded value
117             out.append("%s:: %s" % (l[0], l[1]))
118
119     return "\n".join(out)
120
121
122 def __transform_entry(entry):
123     """Perform required transformations to the Microsoft-provided LDIF"""
124
125     temp_entry = []
126
127     for l in entry:
128         t = []
129
130         if l.find("::") != -1:
131             # This is a base64-encoded value
132             t = l.split(":: ", 1)
133             t.append(1)
134         else:
135             t = l.split(": ", 1)
136             t.append(0)
137
138         key = t[0].lower()
139
140         if key == "changetype":
141             continue
142
143         if key == "distinguishedname":
144             continue
145
146         if key == "instancetype":
147             continue
148
149         if key == "name":
150             continue
151
152         if key == "cn":
153             continue
154
155         if key == "objectcategory":
156             continue
157
158         if key == "showinadvancedviewonly":
159             value = t[1].upper().lstrip().rstrip()
160             if value == "TRUE":
161                 # Remove showInAdvancedViewOnly attribute if it is set to the
162                 # default value of TRUE
163                 continue
164
165         t[1] = fix_dn(t[1])
166
167         temp_entry.append(t)
168
169     entry = temp_entry
170
171     return entry
172
173
174 def read_ms_ldif(filename):
175     """Read and transform Microsoft-provided LDIF file."""
176
177     out = []
178
179     from io import open
180     f = open(filename, "r", encoding='latin-1')
181     for entry in __read_raw_entries(f):
182         out.append(__write_ldif_one(__transform_entry(entry)))
183
184     return "\n\n".join(out) + "\n\n"
185
186
187 if __name__ == '__main__':
188     import sys
189
190     try:
191         display_specifiers_file = sys.argv[1]
192     except IndexError:
193         print("Usage: %s display-specifiers-ldif-file.txt" % (sys.argv[0]), file=sys.stderr)
194         sys.exit(1)
195
196     print(read_ms_ldif(display_specifiers_file))