Use SASL/EXTERNAL over ldapi://
[nivanova/samba-autobuild/.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
21 import re
22
23 def __read_folded_line(f, buffer):
24     """Read a line from an LDIF file, unfolding it"""
25     line = buffer
26
27     while True:
28         l = f.readline()
29
30         if l[:1] == " ":
31             # continued line
32
33             # cannot fold an empty line
34             assert(line != "" and line != "\n")
35
36             # preserves '\n '
37             line = line + l
38         else:
39             # non-continued line
40             if line == "":
41                 line = l
42
43                 if l == "":
44                     # eof, definitely won't be folded
45                     break
46             else:
47                 # marks end of a folded line
48                 # line contains the now unfolded line
49                 # buffer contains the start of the next possibly folded line
50                 buffer = l
51                 break
52
53     return (line, buffer)
54
55 # Only compile regexp once.
56 # Will not match options after the attribute type.
57 attr_type_re = re.compile("^([A-Za-z][A-Za-z0-9-]*):")
58
59 def __read_raw_entries(f):
60     """Read an LDIF entry, only unfolding lines"""
61
62     buffer = ""
63
64     while True:
65         entry = []
66
67         while True:
68             (l, buffer) = __read_folded_line(f, buffer)
69
70             if l[:1] == "#":
71                 continue
72
73             if l == "\n" or l == "":
74                 break
75
76             m = attr_type_re.match(l)
77
78             if m:
79                 if l[-1:] == "\n":
80                     l = l[:-1]
81
82                 entry.append(l)
83             else:
84                 print >>sys.stderr, "Invalid line: %s" % l,
85                 sys.exit(1)
86
87         if len(entry):
88             yield entry
89
90         if l == "":
91             break
92
93 def fix_dn(dn):
94     """Fix a string DN to use ${CONFIGDN}"""
95
96     if dn.find("<Configuration NC Distinguished Name>") != -1:
97         dn = dn.replace("\n ", "")
98         return dn.replace("<Configuration NC Distinguished Name>", "${CONFIGDN}")
99     else:
100         return dn
101
102 def __write_ldif_one(entry):
103     """Write out entry as LDIF"""
104     out = []
105
106     for l in entry:
107         if l[2] == 0:
108             out.append("%s: %s" % (l[0], l[1]))
109         else:
110             # This is a base64-encoded value
111             out.append("%s:: %s" % (l[0], l[1]))
112
113     return "\n".join(out)
114
115 def __transform_entry(entry):
116     """Perform required transformations to the Microsoft-provided LDIF"""
117
118     temp_entry = []
119
120     for l in entry:
121         t = []
122
123         if l.find("::") != -1:
124             # This is a base64-encoded value
125             t = l.split(":: ", 1)
126             t.append(1)
127         else:
128             t = l.split(": ", 1)
129             t.append(0)
130
131         key = t[0].lower()
132
133         if key == "changetype":
134             continue
135
136         if key == "distinguishedname":
137             continue
138
139         if key == "instancetype":
140             continue
141
142         if key == "name":
143             continue
144
145         if key == "cn":
146             continue
147
148         if key == "objectcategory":
149             continue
150
151         if key == "showinadvancedviewonly":
152             value = t[1].upper().lstrip().rstrip()
153             if value == "TRUE":
154                 # Remove showInAdvancedViewOnly attribute if it is set to the
155                 # default value of TRUE
156                 continue
157
158         t[1] = fix_dn(t[1])
159
160         temp_entry.append(t)
161
162     entry = temp_entry
163
164     return entry
165
166 def read_ms_ldif(filename):
167     """Read and transform Microsoft-provided LDIF file."""
168
169     out = []
170
171     f = open(filename, "rU")
172     for entry in __read_raw_entries(f):
173         out.append(__write_ldif_one(__transform_entry(entry)))
174
175     return "\n\n".join(out) + "\n\n"
176
177 if __name__ == '__main__':
178     import sys
179
180     try:
181         display_specifiers_file = sys.argv[1]
182     except IndexError:
183         print >>sys.stderr, "Usage: %s display-specifiers-ldif-file.txt" % (sys.argv[0])
184         sys.exit(1)
185
186     print read_ms_ldif(display_specifiers_file)
187