Statistiques
| Révision:

root / LicensesMercure / LDAP.pas @ 1

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.