root / LicensesMercure / LDAP.pas
Historique | Voir | Annoter | Télécharger (10,006 ko)
1 |
unit LDAP;
|
---|---|
2 |
|
3 |
{
|
4 |
LDAP Simple Authentification (c)2004 by Paul TOTH <tothpaul@free.fr>
|
5 |
http://tothpaul.free.fr
|
6 |
}
|
7 |
|
8 |
{
|
9 |
This program is free software; you can redistribute it and/or
|
10 |
modify it under the terms of the GNU General Public License
|
11 |
as published by the Free Software Foundation; either version 2
|
12 |
of the License, or (at your option) any later version.
|
13 |
|
14 |
This program is distributed in the hope that it will be useful,
|
15 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17 |
GNU General Public License for more details.
|
18 |
|
19 |
You should have received a copy of the GNU General Public License
|
20 |
along with this program; if not, write to the Free Software
|
21 |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
22 |
}
|
23 |
|
24 |
interface
|
25 |
|
26 |
// http://abcdrfc.free.fr/rfc-vf/rfc2251.html
|
27 |
|
28 |
uses
|
29 |
Dialogs,Winsock,SysUtils; |
30 |
|
31 |
function LDAPOpen(Server:string; Port:integer=389):integer; |
32 |
function LDAPBind(LDAP:integer; Name,Password:string):boolean; |
33 |
function LDAPWhoAmI(LDAP:integer):string; |
34 |
function LDAPCaps(LDAP:integer):string; |
35 |
function LDAPSearch(LDAP:integer; Name:string):string; |
36 |
function LDAPAttribute(LDAP:integer; DN,Attribute:string):string; |
37 |
procedure LDAPClose(var LDAP:integer); |
38 |
|
39 |
implementation
|
40 |
|
41 |
const
|
42 |
LDAP_BOOLEAN =#$01;
|
43 |
LDAP_INTEGER =#$02;
|
44 |
LDAP_STRING =#$04;
|
45 |
LDAP_NULL =#$05;
|
46 |
LDAP_ENUM =#$0A;
|
47 |
|
48 |
LDAP_SEQUENCE =#$30;
|
49 |
LDAP_SET =#$31;
|
50 |
|
51 |
LDAP_BIND =#$60;
|
52 |
LDAP_BIND_REPLY =#$61;
|
53 |
LDAP_SEARCH =#$63;
|
54 |
LDAP_SEARCH_ENTRY=#$64;
|
55 |
LDAP_SEARCH_DONE =#$65;
|
56 |
LDAP_EXTENDED =#$77;
|
57 |
|
58 |
LDAP_FILTER_ANY =#$87;
|
59 |
LDAP_FILTER_OR =#$A1;
|
60 |
LDAP_FILTER_MATCH=#$A3;
|
61 |
|
62 |
LDAP_FALSE = #$00;
|
63 |
LDAP_TRUE = #$FF;
|
64 |
|
65 |
LDAP_WHOAMI = '1.3.6.1.4.1.4203.1.11.3';
|
66 |
|
67 |
procedure WSAStartup;
|
68 |
var
|
69 |
WSA:TWSAData; |
70 |
begin
|
71 |
Winsock.WSAStartup($101,WSA);
|
72 |
end;
|
73 |
|
74 |
function INetAddr(Host:pansichar):integer;
|
75 |
var
|
76 |
PHost:PHostEnt; |
77 |
begin
|
78 |
Result:=inet_addr(Host); |
79 |
if Result=INADDR_NONE then begin |
80 |
PHost:=gethostbyname(Host); |
81 |
if PHost=nil then exit; |
82 |
Result:=integer(pointer(PHost.h_addr^)^); |
83 |
end;
|
84 |
end;
|
85 |
|
86 |
function SendData(Socket:integer; var Data; Size:integer):integer; |
87 |
var
|
88 |
p:pchar; |
89 |
i:integer; |
90 |
begin
|
91 |
Result:=Size; |
92 |
p:=@Data; |
93 |
while Size>0 do begin |
94 |
i:=send(Socket,p^,Size,0);
|
95 |
if i<=0 then begin |
96 |
Result:=i; |
97 |
exit; |
98 |
end;
|
99 |
dec(Size,i); |
100 |
inc(p,i); |
101 |
end;
|
102 |
end;
|
103 |
|
104 |
function ReadData(Socket:integer; var Str:string; Min:integer):boolean; |
105 |
var
|
106 |
l:integer; |
107 |
i:integer; |
108 |
b:array[0..1023] of char; |
109 |
begin
|
110 |
l:=Length(Str); |
111 |
while l<Min do begin |
112 |
i:=recv(Socket,b,SizeOf(b),0);
|
113 |
if i<=0 then begin |
114 |
Result:=False; |
115 |
exit; |
116 |
end;
|
117 |
SetLength(Str,l+i); |
118 |
Move(b,Str[l+1],i);
|
119 |
inc(l,i); |
120 |
end;
|
121 |
Result:=True; |
122 |
end;
|
123 |
|
124 |
function BinToInt(var Data; Size:integer):integer; |
125 |
var
|
126 |
b:^byte; |
127 |
begin
|
128 |
b:=@Data; |
129 |
Result:=b^; |
130 |
while Size>1 do begin |
131 |
Result:=Result shl 8+b^; |
132 |
dec(Size); |
133 |
end;
|
134 |
end;
|
135 |
|
136 |
function Chunk(Code:char; Data:string):string; |
137 |
var
|
138 |
len :integer; |
139 |
begin
|
140 |
len:=Length(Data); |
141 |
Result:=chr(Len and $FF); |
142 |
if len>=128 then begin |
143 |
while Len>255 do begin |
144 |
Len:=Len shr 8; |
145 |
Result:=chr(Len and $FF)+Result; |
146 |
end;
|
147 |
Result:=chr($80+Length(Result))+Result;
|
148 |
end;
|
149 |
Result:=Code+Result+Data; |
150 |
end;
|
151 |
|
152 |
function GetChunk(Code:char; var Data,Chunk:string):boolean; |
153 |
var
|
154 |
Head,Size:integer; |
155 |
begin
|
156 |
Result:=False; |
157 |
if (Data='')or(Data[1]<>Code) then exit; |
158 |
Head:=2;
|
159 |
Size:=ord(Data[Head]); |
160 |
if Size>=128 then begin |
161 |
Head:=2+Size and $7F; |
162 |
Size:=BinToInt(Data[3],Head-2); |
163 |
end;
|
164 |
Chunk:=Copy(Data,Head+1,Size);
|
165 |
Delete(Data,1,Head+Size);
|
166 |
Result:=True; |
167 |
end;
|
168 |
|
169 |
function StrChunk(Var Data:string):string; |
170 |
begin
|
171 |
GetChunk(LDAP_STRING,Data,Result); |
172 |
end;
|
173 |
|
174 |
function IntChunk(var Data:string):integer; |
175 |
var
|
176 |
Chunk:string;
|
177 |
begin
|
178 |
if GetChunk(LDAP_INTEGER,Data,Chunk) then |
179 |
Result:=BinToInt(Chunk[1],Length(Chunk))
|
180 |
else
|
181 |
Result:=-1;
|
182 |
end;
|
183 |
|
184 |
function EnumChunk(var Data:string):integer; |
185 |
var
|
186 |
Chunk:string;
|
187 |
begin
|
188 |
if GetChunk(LDAP_ENUM,Data,Chunk) then |
189 |
Result:=BinToInt(Chunk[1],Length(Chunk))
|
190 |
else
|
191 |
Result:=-1;
|
192 |
end;
|
193 |
|
194 |
function OpenChunk(Code:char; var Data:string):boolean; |
195 |
var
|
196 |
Chunk:string;
|
197 |
begin
|
198 |
Result:=False; |
199 |
Chunk:=Data; |
200 |
if not GetChunk(Code,Chunk,Data) then exit; |
201 |
if Chunk<>'' then exit; |
202 |
Result:=True; |
203 |
end;
|
204 |
|
205 |
function ReadSequence(LDAP:integer; var Str,Left:string; Sequence:integer):boolean; |
206 |
var
|
207 |
Size:integer; |
208 |
Head:integer; |
209 |
begin
|
210 |
Result:=False; |
211 |
// minimum Header
|
212 |
Head:=2;
|
213 |
if ReadData(LDAP,Str,Head)=False then exit; |
214 |
// Sequence
|
215 |
if Str[1]<>LDAP_SEQUENCE then exit; |
216 |
// Single byte size
|
217 |
Size:=ord(Str[2]);
|
218 |
// Multiple byte Size
|
219 |
if Size>=128 then begin |
220 |
Head:=2+Size and $7F; |
221 |
if ReadData(LDAP,Str,Head)=False then exit; |
222 |
Size:=BinToInt(Str[3],Head-2); |
223 |
end;
|
224 |
// Read whole Sequence
|
225 |
if ReadData(LDAP,Str,Head+Size)=False then exit; |
226 |
// drop Sequence header
|
227 |
Delete(Str,1,Head);
|
228 |
Left:=Copy(Str,Size+1,MaxInt);
|
229 |
SetLength(Str,Size); |
230 |
// Skip Sequence number
|
231 |
if IntChunk(Str)<>Sequence then exit; |
232 |
// Ok !
|
233 |
Result:=True; |
234 |
end;
|
235 |
|
236 |
function LDAPOpen(Server:string; Port:integer=389):integer; |
237 |
var
|
238 |
SockAddr:TSockAddr; |
239 |
begin
|
240 |
Result:=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); |
241 |
if Result=INVALID_SOCKET then exit; |
242 |
FillChar(SockAddr,SizeOf(SockAddr),0);
|
243 |
SockAddr.sin_family:=AF_INET; |
244 |
SockAddr.sin_addr.S_addr:=INetAddr(pansichar(Server)); |
245 |
SockAddr.sin_port:=htons(Port); |
246 |
if connect(Result,SockAddr,SizeOf(SockAddr))<>0 then LDAPClose(Result); |
247 |
end;
|
248 |
|
249 |
function LDAPBind(LDAP:integer; Name,Password:string):boolean; |
250 |
var
|
251 |
s1,s2:string;
|
252 |
begin
|
253 |
Result:=False; |
254 |
s1:=Chunk(LDAP_SEQUENCE, |
255 |
Chunk(LDAP_INTEGER,#1)+ // Message ID 1 |
256 |
Chunk(LDAP_BIND, // Bind
|
257 |
Chunk(LDAP_INTEGER,#3)+ // LDAP version 3 |
258 |
Chunk(LDAP_STRING,Name)+ // UserName
|
259 |
Chunk(#$80,Password) // Password |
260 |
) |
261 |
); |
262 |
if SendData(LDAP,s1[1],Length(s1))<=0 then exit; |
263 |
s1:='';
|
264 |
if not ReadSequence(LDAP,s1,s2,1) then exit; |
265 |
if s2<>'' then exit; |
266 |
if (OpenChunk(LDAP_BIND_REPLY,s1)=False) then exit; // Bind Response |
267 |
Result:=EnumChunk(s1)=0; // OK |
268 |
//StrChunk(s1); // DN
|
269 |
//StrChunk(s1); // ResultString
|
270 |
end;
|
271 |
|
272 |
function LDAPWhoAmI(LDAP:integer):string; |
273 |
var
|
274 |
s1,s2:string;
|
275 |
begin
|
276 |
s1:=Chunk(LDAP_SEQUENCE, |
277 |
Chunk(LDAP_INTEGER,#4)+ // Message ID 4 |
278 |
Chunk(LDAP_EXTENDED, // Extension
|
279 |
Chunk(#$80,LDAP_WHOAMI)
|
280 |
) |
281 |
); |
282 |
if SendData(LDAP,s1[1],Length(s1))<=0 then exit; |
283 |
s1:='';
|
284 |
if not ReadSequence(LDAP,s1,s2,4) then exit; |
285 |
Result:=s1; |
286 |
end;
|
287 |
|
288 |
function LDAPCaps(LDAP:integer):string; |
289 |
var
|
290 |
s1,s2,s3:string;
|
291 |
begin
|
292 |
s1:=Chunk(LDAP_SEQUENCE, // SEQUENCE
|
293 |
Chunk(LDAP_INTEGER,#2)+ // Message ID 2 |
294 |
Chunk(LDAP_SEARCH, // Search
|
295 |
Chunk(LDAP_STRING,'')+ // BaseObject |
296 |
Chunk(LDAP_ENUM,#0)+ // Scope 2 = Whole Tree |
297 |
Chunk(LDAP_ENUM,#3)+ // Aliases 0 = derefaliases |
298 |
Chunk(LDAP_INTEGER,#0)+ // Size limite |
299 |
Chunk(LDAP_INTEGER,#0)+ // Time limite |
300 |
Chunk(LDAP_BOOLEAN,LDAP_FALSE)+ // Type only (boolean)
|
301 |
Chunk(LDAP_FILTER_ANY,'objectClass')+
|
302 |
Chunk(LDAP_SEQUENCE, |
303 |
Chunk(LDAP_STRING,'supportedCapabilities')
|
304 |
) |
305 |
) |
306 |
); |
307 |
if SendData(LDAP,s1[1],Length(s1))<=0 then exit; |
308 |
s1:='';
|
309 |
if not ReadSequence(LDAP,s1,s2,2) then exit; |
310 |
if not OpenChunk(LDAP_SEARCH_ENTRY,s1) then exit; |
311 |
if not ReadSequence(LDAP,s2,s3,2) then exit; |
312 |
if s3<>'' then exit; |
313 |
if not OpenChunk(LDAP_SEARCH_DONE,s2) then exit; // Search Done |
314 |
Result:=s1; |
315 |
end;
|
316 |
|
317 |
function LDAPSearch(LDAP:integer; Name:string):string; |
318 |
var
|
319 |
s1,s2,s3:string;
|
320 |
begin
|
321 |
Result:='';
|
322 |
s1:=Chunk(LDAP_SEQUENCE, // SEQUENCE
|
323 |
Chunk(LDAP_INTEGER,#2)+ // Message ID 2 |
324 |
Chunk(LDAP_SEARCH, // Search
|
325 |
Chunk(LDAP_STRING,'')+ // BaseObject |
326 |
Chunk(LDAP_ENUM,#2)+ // Scope 2 = Whole Tree |
327 |
Chunk(LDAP_ENUM,#0)+ // Aliases 0 = derefaliases |
328 |
Chunk(LDAP_INTEGER,#0)+ // Size limite |
329 |
Chunk(LDAP_INTEGER,#0)+ // Time limite |
330 |
Chunk(LDAP_BOOLEAN,LDAP_FALSE)+ // Type only (boolean)
|
331 |
Chunk(LDAP_FILTER_OR, // Filter = OR
|
332 |
Chunk(LDAP_FILTER_MATCH, // Filter = Equality Match
|
333 |
Chunk(LDAP_STRING,'cn')+ // common name |
334 |
Chunk(LDAP_STRING,Name) |
335 |
)+ |
336 |
Chunk(LDAP_FILTER_MATCH, // Filter = Equality Match
|
337 |
Chunk(LDAP_STRING,'uid')+ // unique id |
338 |
Chunk(LDAP_STRING,Name) |
339 |
) |
340 |
)+ |
341 |
Chunk(LDAP_SEQUENCE, |
342 |
Chunk(LDAP_NULL,'') // NULL |
343 |
) |
344 |
) |
345 |
); |
346 |
if SendData(LDAP,s1[1],Length(s1))<=0 then exit; |
347 |
s1:='';
|
348 |
if not ReadSequence(LDAP,s1,s2,2) then exit; |
349 |
if not OpenChunk(LDAP_SEARCH_ENTRY,s1) then exit; |
350 |
if not ReadSequence(LDAP,s2,s3,2) then exit; |
351 |
if s3<>'' then exit; |
352 |
if not OpenChunk(LDAP_SEARCH_DONE,s2) then exit; // Search Done |
353 |
Result:=StrChunk(s1); |
354 |
end;
|
355 |
|
356 |
function LDAPAttribute(LDAP:integer; DN,Attribute:string):string; |
357 |
var
|
358 |
s1,s2,s3:string;
|
359 |
begin
|
360 |
s1:=Chunk(LDAP_SEQUENCE, // SEQUENCE
|
361 |
Chunk(LDAP_INTEGER,#3)+ // Message ID 2 |
362 |
Chunk(LDAP_SEARCH, // Search
|
363 |
Chunk(LDAP_STRING,DN)+ // BaseObject
|
364 |
Chunk(LDAP_ENUM,#0)+ // Scope 0 = BaseObject |
365 |
Chunk(LDAP_ENUM,#0)+ // Aliases 0 = derefaliases |
366 |
Chunk(LDAP_INTEGER,#0)+ // Size limite |
367 |
Chunk(LDAP_INTEGER,#0)+ // Time limite |
368 |
Chunk(LDAP_BOOLEAN,LDAP_FALSE)+ // Type only (boolean)
|
369 |
Chunk(LDAP_FILTER_ANY,'objectClass')+ // (objectClass=*) |
370 |
Chunk(LDAP_SEQUENCE, // Sub-Sequence
|
371 |
Chunk(LDAP_STRING,Attribute) |
372 |
) |
373 |
) |
374 |
); |
375 |
if SendData(LDAP,s1[1],Length(s1))<=0 then exit; |
376 |
s1:='';
|
377 |
if not ReadSequence(LDAP,s1,s2,3) then exit; |
378 |
if not OpenChunk(LDAP_SEARCH_ENTRY,s1) then exit; |
379 |
if not ReadSequence(LDAP,s2,s3,3) then exit; |
380 |
if s3<>'' then exit; |
381 |
if not OpenChunk(LDAP_SEARCH_DONE,s2) then exit; // Search Done |
382 |
if StrChunk(s1)<>DN then exit; // DN |
383 |
if not OpenChunk(LDAP_SEQUENCE,s1) then exit; // Sequence of Sequence |
384 |
if not OpenChunk(LDAP_SEQUENCE,s1) then exit; // Sequence |
385 |
if UpperCase(StrChunk(s1))<>UpperCase(Attribute) then exit; |
386 |
if not OpenChunk(LDAP_SET,s1) then exit; // Set of |
387 |
Result:=StrChunk(s1); |
388 |
end;
|
389 |
|
390 |
procedure LDAPClose(var LDAP:integer); |
391 |
begin
|
392 |
closesocket(LDAP); |
393 |
LDAP:=INVALID_SOCKET; |
394 |
end;
|
395 |
|
396 |
initialization
|
397 |
WSAStartup; |
398 |
finalization
|
399 |
WSACleanup; |
400 |
end.
|