Source file ldap_schemaparser.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
open Ldap_schemalexer;;
module Oid =
(struct
type t = string
let of_string s = s
let to_string oid = oid
let compare x y = String.compare (to_string x) (to_string y)
end
:
sig
type t
val of_string: string -> t
val to_string: t -> string
val compare: t -> t -> int
end);;
let format_oid id =
Format.open_box 0;
Format.print_string ("<oid " ^ Oid.to_string id ^ ">");
Format.close_box ()
module Lcstring =
(struct
type t = string
let of_string s = String.lowercase_ascii s
let to_string x = x
let compare x y = String.compare x y
end
:
sig
type t
val of_string: string -> t
val to_string: t -> string
val compare: t -> t -> int
end);;
let format_lcstring id =
Format.open_box 0;
Format.print_string ("<lcstring " ^ Lcstring.to_string id ^ ">");
Format.close_box ()
type octype = Abstract | Structural | Auxiliary;;
type objectclass = {oc_name: string list;
oc_oid:Oid.t;
oc_desc:string;
oc_obsolete:bool;
oc_sup:Lcstring.t list;
oc_must:Lcstring.t list;
oc_may:Lcstring.t list;
oc_type:octype;
oc_xattr:string list}
type attribute = {at_name:string list;
at_desc:string;
at_oid:Oid.t;
at_equality:string;
at_ordering:string;
at_substr:Oid.t;
at_syntax:Oid.t;
at_length: Int64.t;
at_obsolete:bool;
at_single_value:bool;
at_collective:bool;
at_no_user_modification:bool;
at_usage:string;
at_sup:Lcstring.t list;
at_xattr:string list};;
type schema = {objectclasses: (Lcstring.t, objectclass) Hashtbl.t;
objectclasses_byoid: (Oid.t, objectclass) Hashtbl.t;
attributes: (Lcstring.t, attribute) Hashtbl.t;
attributes_byoid: (Oid.t, attribute) Hashtbl.t};;
exception Depth
let schema_print_depth = ref 10
let format_schema s =
let indent = 3 in
let printtbl tbl =
let i = ref 0 in
try
Hashtbl.iter
(fun aname _aval ->
if !i < !schema_print_depth then begin
Format.print_string ("<KEY " ^ (Lcstring.to_string aname) ^ ">");
Format.print_break 1 indent;
i := !i + 1
end
else raise Depth)
tbl
with Depth -> Format.print_string "..."
in
Format.open_box 0;
Format.print_string "{objectclasses = <HASHTBL ";
Format.print_break 0 indent;
printtbl s.objectclasses;
Format.print_string ">;";
Format.print_break 0 1;
Format.print_string "objectclasses_byoid = <HASHTBL ...>;";
Format.print_break 0 1;
Format.print_string "attributes = <HASHTBL ";
Format.print_break 0 indent;
printtbl s.attributes;
Format.print_string ">;";
Format.print_break 0 1;
Format.print_string "attributes_byoid = <HASHTBL ...>}";
Format.close_box ()
exception Parse_error_oc of Lexing.lexbuf * objectclass * string;;
exception Parse_error_at of Lexing.lexbuf * attribute * string;;
exception Syntax_error_oc of Lexing.lexbuf * objectclass * string;;
exception Syntax_error_at of Lexing.lexbuf * attribute * string;;
let readSchema oclst attrlst =
let empty_oc = {oc_name=[];oc_oid=Oid.of_string "";oc_desc="";oc_obsolete=false;oc_sup=[];
oc_must=[];oc_may=[];oc_type=Abstract;oc_xattr=[]}
in
let empty_attr = {at_name=[];at_oid=Oid.of_string "";at_desc="";at_equality="";at_ordering="";
at_usage=""; at_substr=Oid.of_string "";at_syntax=Oid.of_string "";
at_length=0L;at_obsolete=false;at_single_value=false;
at_collective=false;at_no_user_modification=false;at_sup=[];at_xattr=[]}
in
let readOc lxbuf oc =
let rec readOptionalFields lxbuf oc =
try match (lexoc lxbuf) with
Name s -> readOptionalFields lxbuf {oc with oc_name=s}
| Desc s -> readOptionalFields lxbuf {oc with oc_desc=s}
| Obsolete -> readOptionalFields lxbuf {oc with oc_obsolete=true}
| Sup s -> (readOptionalFields
lxbuf
{oc with oc_sup=(List.rev_map (Lcstring.of_string) s)})
| Ldap_schemalexer.Abstract -> readOptionalFields lxbuf {oc with oc_type=Abstract}
| Ldap_schemalexer.Structural -> readOptionalFields lxbuf {oc with oc_type=Structural}
| Ldap_schemalexer.Auxiliary -> readOptionalFields lxbuf {oc with oc_type=Auxiliary}
| Must s -> (readOptionalFields
lxbuf
{oc with oc_must=(List.rev_map (Lcstring.of_string) s)})
| May s -> (readOptionalFields
lxbuf
{oc with oc_may=(List.rev_map (Lcstring.of_string) s)})
| Xstring t -> (readOptionalFields
lxbuf
{oc with oc_xattr=(t :: oc.oc_xattr)})
| Rparen -> oc
| _ -> raise (Parse_error_oc (lxbuf, oc, "unexpected token"))
with Failure(_) -> raise (Parse_error_oc (lxbuf, oc, "Expected right parenthesis"))
in
let readOid lxbuf oc =
try match (lexoc lxbuf) with
Numericoid(s) -> readOptionalFields lxbuf {oc with oc_oid=Oid.of_string s}
| _ -> raise (Parse_error_oc (lxbuf, oc, "missing required field, numericoid"))
with Failure(_) -> raise (Syntax_error_oc (lxbuf, oc, "Syntax error"))
in
let readLparen lxbuf oc =
try match (lexoc lxbuf) with
Lparen -> readOid lxbuf oc
| _ -> raise (Parse_error_oc (lxbuf, oc, "Expected left paren"))
with Failure(_) -> raise (Syntax_error_oc (lxbuf, oc, "Syntax error"))
in
readLparen lxbuf oc
in
let rec readOcs oclst schema =
match oclst with
a :: l -> let oc = readOc (Lexing.from_string a) empty_oc in
List.iter (fun n -> Hashtbl.add schema.objectclasses (Lcstring.of_string n) oc) oc.oc_name;
Hashtbl.add schema.objectclasses_byoid oc.oc_oid oc;readOcs l schema
| [] -> ()
in
let readAttr lxbuf attr =
let rec readOptionalFields lxbuf attr =
try match (lexattr lxbuf) with
Name s -> readOptionalFields lxbuf {attr with at_name=s}
| Desc s -> readOptionalFields lxbuf {attr with at_desc=s}
| Obsolete -> readOptionalFields lxbuf {attr with at_obsolete=true}
| Sup s ->
readOptionalFields lxbuf {attr with at_sup=(List.rev_map (Lcstring.of_string) s)}
| Equality s -> readOptionalFields lxbuf {attr with at_equality=s}
| Substr s -> readOptionalFields lxbuf {attr with at_substr=Oid.of_string s}
| Ordering s -> readOptionalFields lxbuf {attr with at_ordering=s}
| Syntax (s, l) ->
readOptionalFields lxbuf {attr with at_syntax=Oid.of_string s;at_length=l}
| Single_value -> readOptionalFields lxbuf {attr with at_single_value=true}
| Collective -> readOptionalFields lxbuf {attr with at_collective=true}
| No_user_modification -> readOptionalFields lxbuf {attr with at_no_user_modification=true}
| Usage s -> readOptionalFields lxbuf {attr with at_usage=s}
| Rparen -> attr
| Xstring t -> (readOptionalFields
lxbuf
{attr with at_xattr=(t :: attr.at_xattr)})
| _ -> raise (Parse_error_at (lxbuf, attr, "unexpected token"))
with Failure(f) -> raise (Parse_error_at (lxbuf, attr, f))
in
let readOid lxbuf attr =
try match (lexoc lxbuf) with
Numericoid(s) -> readOptionalFields lxbuf {attr with at_oid=Oid.of_string s}
| _ -> raise (Parse_error_at (lxbuf, attr, "missing required field, numericoid"))
with Failure(_) -> raise (Syntax_error_at (lxbuf, attr, "Syntax error"))
in
let readLparen lxbuf attr =
try match (lexoc lxbuf) with
Lparen -> readOid lxbuf attr
| _ -> raise (Parse_error_at (lxbuf, attr, "Expected left paren"))
with Failure(_) -> raise (Syntax_error_at (lxbuf, attr, "Syntax error"))
in
readLparen lxbuf attr
in
let rec readAttrs attrlst schema =
match attrlst with
a :: l -> let attr = readAttr (Lexing.from_string a) empty_attr in
List.iter (fun n -> Hashtbl.add schema.attributes (Lcstring.of_string n) attr) attr.at_name;
Hashtbl.add schema.attributes_byoid attr.at_oid attr;readAttrs l schema
| [] -> ()
in
let schema = {objectclasses=Hashtbl.create 500;
objectclasses_byoid=Hashtbl.create 500;
attributes=Hashtbl.create 5000;
attributes_byoid=Hashtbl.create 5000} in
readAttrs attrlst schema;
readOcs oclst schema;
schema;;