Guest User

Untitled

a guest
Jun 28th, 2018
115
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 30.25 KB | None | 0 0
  1. try
  2. ADSISearch1.Filter := WideString('samaccountname=' + GetUserFromWindows());
  3.  
  4. try
  5. ADSISearch1.Search;
  6. slTemp := ADSISearch1.GetFirstRow();
  7. except
  8. //uh-oh, this is a problem, get out of here
  9. // --- must not have been able to talk to AD
  10. // --- could be the user recently changed pwd and is logged in with
  11. // their cached credentials
  12. // just suppress this exception
  13. bHomeDriveMappingFailed := True;
  14. Result := bSuccess;
  15. Exit;
  16. end;
  17.  
  18. while (slTemp <> nil) do
  19. begin
  20. for ix := 0 to slTemp.Count - 1 do
  21. begin
  22. curLine := AnsiUpperCase(slTemp[ix]);
  23. if AnsiStartsStr('HOMEDIRECTORY', curLine) then
  24. begin
  25. sADHomeDriveUncPath := AnsiReplaceStr(curLine, 'HOMEDIRECTORY=', '');
  26. //sADHomeDriveUncPath := slTemp[ix];
  27. end
  28. else if AnsiStartsStr('HOMEDRIVE', curLine) then
  29. begin
  30. sADHomeDriveLetter := AnsiReplaceStr(curLine, 'HOMEDRIVE=', '');
  31. //sADHomeDriveLetter := slTemp[ix];
  32. end;
  33. end;
  34.  
  35. FreeAndNil(slTemp);
  36. slTemp := ADSISearch1.GetNextRow();
  37. end;
  38. except
  39. //suppress this exception
  40. bHomeDriveMappingFailed := True;
  41. Exit;
  42. end;
  43.  
  44. (* ----------------------------------------------------------------------------
  45. Module: ADSI Searching in Delphi
  46. Author: Marc Scheuner
  47. Date: July 17, 2000
  48.  
  49. Changes:
  50.  
  51. Description:
  52.  
  53. constructor Create(aOwner : TComponent); override;
  54. Creates a new instance of component
  55.  
  56. destructor Destroy; override;
  57. Frees instance of component
  58.  
  59. function CheckIfExists() : Boolean;
  60. Checks to see if the object described in the properties exists or not
  61. TRUE: Object exists, FALSE: object does not exist
  62.  
  63. procedure Search;
  64. Launches the ADSI search - use GetFirstRow and GetNextRow to retrieve information
  65.  
  66. function GetFirstRow() : TWideStringList;
  67. function GetNextRow() : TWideStringList;
  68. Returns the first row / next row of the result set, as a WideStringList.
  69. The values are stored in the string list as a <name>=<value> pair, so you
  70. can access the values via the FWideStringList.Values['name'] construct.
  71.  
  72. Multivalued attributes are returned as one per line, in an array index
  73. manner:
  74. objectClass[0]=top
  75. objectClass[1]=Person
  76. objectClass[2]=organizationalPerson
  77. objectClass[3]=user
  78. and so forth. The index is zero-based.
  79.  
  80. If there are no (more) rows, the return value will be NIL.
  81.  
  82. It's up to the receiver to free the string list when no longer needed.
  83.  
  84. property Attributes : WideString
  85. Defines the attributes you want to retrieve from the object. If you leave
  86. this empty, all available attributes will be returned.
  87. You can specify multiple attributes separated by comma:
  88. cn,distinguishedName,name,ADsPath
  89. will therefore retrieve these four attributes for all the objects returned
  90. in the search (if the attributes exist).
  91.  
  92. property BaseIADs : IADs
  93. If you already have an interface to an IADs object, you can reuse it here
  94. by setting it to the BaseIADs property - in this case, ADSISearch can skip
  95. the step of binding to the ADSI object and will be executing faster.
  96.  
  97. property BasePath : WideString
  98. LDAP base path for the search - the further down in the LDAP tree you start
  99. searching, the smaller the namespace to search and the quicker the search
  100. will return what you're looking for.
  101.  
  102. LDAP://cn=Users,dc=stmaarten,dc=qc,dc=rnd
  103. is the well-known LDAP path for the Users container in the stmaarten.qc.rnd
  104. domain.
  105.  
  106. property ChaseReferrals : Boolean
  107. If set to TRUE, the search might need to connect to other domain controllers
  108. and naming contexts, which is very time consuming.
  109. Set this property to FALSE to limit it to the current naming context, thus
  110. speeding up searches significantly.
  111.  
  112. property DirSrchIntf : IDirectorySearch
  113. Provides access to the basic Directory Search interface, in case you need
  114. to do some low-level tweaking
  115.  
  116. property Filter : WideString
  117. LDAP filter expression to search for. It will be ANDed together with a
  118. (objectClass=<ObjectClass>) filter to form the full search filter.
  119. It can be anything that is a valid LDAP search filter - see the appropriate
  120. books or online help files for details.
  121.  
  122. It can be (among many other things):
  123. cn=Marc*
  124. badPwdCount>=0
  125. countryCode=49
  126. givenName=Steve
  127. and multiple conditions can be ANDed or ORed together using the LDAP syntax.
  128.  
  129. property MaxRows : Integer
  130. Maximum rows of the result set you want to retrieve.
  131. Default is 0 which means all rows.
  132.  
  133. property PageSize : Integer
  134. Maximum number of elements to be returned in a paged search. If you set this to 0,
  135. the search will *not* be "paged", e.g. IDirectorySearch will return all elements
  136. found in one big gulp, but there's a limit at 1'000 elements.
  137. With paged searching, you can search and find any number of AD objects. Default is
  138. set to 100 elements. No special need on the side of the developer / user to use
  139. paged searches - just set the PageSize to something non-zero.
  140.  
  141. property ObjectClass: WideString
  142. ObjectClass of the ADSI object you are searching for. This allows you to
  143. specify e.g. just users, only computers etc.
  144. Be aware that ObjectClass is a multivalued attribute in LDAP, and sometimes
  145. has unexpected hierarchies (e.g."computer" descends from "user" and will therefore
  146. show up if you search for object class "user").
  147. This property will be included in the LDAP search filter passed to the
  148. search engine. If you don't want to limit the objects returned, just leave
  149. it at the default value of *
  150.  
  151. property SearchScope
  152. Limits the scope of the search.
  153. scBase: search only the base object (as specified by the LDAP path) - not very
  154. useful.....
  155. scOneLevel: search only object immediately contained by the specified base
  156. object (does not include baes object) - limits the depth of
  157. the search
  158. scSubtree: no limit on how "deep" the search goes, below the specified
  159. base object - this is the default.
  160.  
  161. ---------------------------------------------------------------------------- *)
  162.  
  163. unit ADSISearch;
  164.  
  165. interface
  166.  
  167. uses
  168. ActiveX,
  169. ActiveDs_TLB,
  170. Classes,
  171. SysUtils
  172. {$IFDEF UNICODE}
  173. ,Unicode
  174. {$ENDIF}
  175. ;
  176.  
  177. type
  178. EADSISearchException = class(Exception);
  179.  
  180. TSearchScope = (scBase, scOneLevel, scSubtree);
  181.  
  182. TADSISearch = class(TComponent)
  183. private
  184. FBaseIADs : IADs;
  185. FDirSrchIntf : IDirectorySearch;
  186. FSearchHandle : ADS_SEARCH_HANDLE;
  187. FAttributes,
  188. FFilter,
  189. FBasePath,
  190. FObjectClass : Widestring;
  191. FResult : HRESULT;
  192. FChaseReferrals,
  193. FSearchExecuted : Boolean;
  194. FMaxRows,
  195. FPageSize : Integer;
  196. FSearchScope : TSearchScope;
  197. FUsername: Widestring;
  198. FPassword: Widestring;
  199.  
  200. {$IFDEF UNICODE}
  201. procedure EnumerateColumns(aStrList : TWideStringList);
  202. {$ELSE}
  203. procedure EnumerateColumns(aStrList : TStringList);
  204. {$ENDIF}
  205.  
  206. function GetStringValue(oSrchColumn : ads_search_column; Index : Integer) : WideString;
  207.  
  208. procedure SetBaseIADs(const Value: IADs);
  209. procedure SetBasePath(const Value: WideString);
  210. procedure SetFilter(const Value: WideString);
  211. procedure SetObjectClass(const Value: Widestring);
  212. procedure SetMaxRows(const Value: Integer);
  213. procedure SetPageSize(const Value: Integer);
  214. procedure SetAttributes(const Value: WideString);
  215. procedure SetChaseReferrals(const Value: Boolean);
  216. procedure SetUsername(const Value: WideString);
  217. procedure SetPassword(const Value: WideString);
  218.  
  219. public
  220. constructor Create(aOwner : TComponent); override;
  221. destructor Destroy; override;
  222.  
  223. function CheckIfExists() : Boolean;
  224. procedure Search;
  225.  
  226. {$IFDEF UNICODE}
  227. function GetFirstRow() : TWideStringList;
  228. function GetNextRow() : TWideStringList;
  229. {$ELSE}
  230. function GetFirstRow() : TStringList;
  231. function GetNextRow() : TStringList;
  232. {$ENDIF}
  233.  
  234. published
  235. // list of attributes to return - empty string equals all attributes
  236. property Attributes : WideString read FAttributes write SetAttributes;
  237.  
  238. // search base - both as an IADs interface, as well as a LDAP path
  239. property BaseIADs : IADs read FBaseIADs write SetBaseIADs stored False;
  240. property BasePath : WideString read FBasePath write SetBasePath;
  241.  
  242. // chase possible referrals to other domain controllers?
  243. property ChaseReferrals : Boolean read FChaseReferrals write SetChaseReferrals default False;
  244.  
  245. // "raw" search interface - for any low-level tweaking necessary
  246. property DirSrchIntf : IDirectorySearch read FDirSrchIntf;
  247.  
  248. // LDAP filter to limit the search
  249. property Filter : WideString read FFilter write SetFilter;
  250.  
  251. // maximum number of rows to return - 0 = all rows (no limit)
  252. property MaxRows : Integer read FMaxRows write SetMaxRows default 0;
  253. property ObjectClass : Widestring read FObjectClass write SetObjectClass;
  254. property PageSize : Integer read FPageSize write SetPageSize default 100;
  255. property SearchScope : TSearchScope read FSearchScope write FSearchScope default scSubtree;
  256. property Username : Widestring read FUsername write SetUsername;
  257. property Password : Widestring read FPassword write SetPassword;
  258. end;
  259.  
  260. const
  261. // ADSI success codes
  262. S_ADS_ERRORSOCCURRED = $00005011;
  263. S_ADS_NOMORE_ROWS = $00005012;
  264. S_ADS_NOMORE_COLUMNS = $00005013;
  265.  
  266. // ADSI error codes
  267. E_ADS_BAD_PATHNAME = $80005000;
  268. E_ADS_INVALID_DOMAIN_OBJECT = $80005001;
  269. E_ADS_INVALID_USER_OBJECT = $80005002;
  270. E_ADS_INVALID_COMPUTER_OBJECT = $80005003;
  271. E_ADS_UNKNOWN_OBJECT = $80005004;
  272. E_ADS_PROPERTY_NOT_SET = $80005005;
  273. E_ADS_PROPERTY_NOT_SUPPORTED = $80005006;
  274. E_ADS_PROPERTY_INVALID = $80005007;
  275. E_ADS_BAD_PARAMETER = $80005008;
  276. E_ADS_OBJECT_UNBOUND = $80005009;
  277. E_ADS_PROPERTY_NOT_MODIFIED = $8000500A;
  278. E_ADS_PROPERTY_MODIFIED = $8000500B;
  279. E_ADS_CANT_CONVERT_DATATYPE = $8000500C;
  280. E_ADS_PROPERTY_NOT_FOUND = $8000500D;
  281. E_ADS_OBJECT_EXISTS = $8000500E;
  282. E_ADS_SCHEMA_VIOLATION = $8000500F;
  283. E_ADS_COLUMN_NOT_SET = $80005010;
  284. E_ADS_INVALID_FILTER = $80005014;
  285.  
  286. procedure Register;
  287.  
  288.  
  289. (*============================================================================*)
  290. (* IMPLEMENTATION *)
  291. (*============================================================================*)
  292.  
  293. implementation
  294.  
  295. uses
  296. Windows;
  297.  
  298. var
  299. ActiveDSHandle : THandle;
  300. gADsGetObject: function(pwcPathName: PWideChar; const xRIID: TGUID; out pVoid): HResult; stdcall;
  301. gFreeADsMem : function(aPtr : Pointer) : BOOL; stdcall;
  302.  
  303.  
  304. // Active Directory API helper functions - implemented in ActiveDs.DLL and
  305. // dynamically loaded at time of initialization of this module
  306.  
  307. function ADsGetObject(pwcPathName: PWideChar; const xRIID: TGUID; var pVoid): HResult;
  308. begin
  309. Result := gADsGetObject(pwcPathName, xRIID, pVoid);
  310. end;
  311.  
  312. function FreeADsMem(aPtr : Pointer) : BOOL;
  313. begin
  314. Result := gFreeADsMem(aPtr);
  315. end;
  316.  
  317.  
  318. // resource strings for all messages - makes localization so much easier!
  319.  
  320. resourcestring
  321. rc_CannotLoadActiveDS = 'Cannot load ActiveDS.DLL';
  322. rc_CannotGetProcAddress = 'Cannot GetProcAddress of ';
  323.  
  324. rc_CouldNotBind = 'Could not bind to object %s (%x)';
  325. rc_CouldNotFreeSH = 'Could not free search handle (%x)';
  326. rc_CouldNotGetIDS = 'Could not obtain IDirectorySearch interface for %s (%x)';
  327. rc_GetFirstFailed = 'GetFirstRow failed (%x)';
  328. rc_GetNextFailed = 'GetNextRow failed (%x)';
  329. rc_SearchFailed = 'Search in ADSI failed (result code %x)';
  330. rc_SearchNotExec = 'Search has not been executed yet';
  331. rc_SetSrchPrefFailed = 'Setting the max row limit failed (%x)';
  332. rc_UnknownDataType = '(unknown data type %d)';
  333.  
  334. // ---------------------------------------------------------------------------
  335. // Constructor and destructor
  336. // ---------------------------------------------------------------------------
  337.  
  338. constructor TADSISearch.Create(aOwner : TComponent);
  339. begin
  340. inherited Create(aOwner);
  341.  
  342. FBaseIADs := nil;
  343. FDirSrchIntf := nil;
  344.  
  345. FAttributes := '';
  346. FBasePath := '';
  347. FFilter := '';
  348. FObjectClass := '*';
  349.  
  350. FMaxRows := 0;
  351. FPageSize := 100;
  352.  
  353. FChaseReferrals := False;
  354. FSearchScope := scSubtree;
  355.  
  356. FSearchExecuted := False;
  357. end;
  358.  
  359. destructor TADSISearch.Destroy;
  360. begin
  361. if (FSearchHandle <> 0) then
  362. FResult := FDirSrchIntf.CloseSearchHandle(FSearchHandle);
  363.  
  364. FBaseIADs := nil;
  365. FDirSrchIntf := nil;
  366.  
  367. inherited;
  368. end;
  369.  
  370. // ---------------------------------------------------------------------------
  371. // Set and Get methods
  372. // ---------------------------------------------------------------------------
  373.  
  374. procedure TADSISearch.SetPassword(const Value: WideString);
  375. begin
  376. if (FPassword <> Value) then
  377. begin
  378. FPassword := Value;
  379. end;
  380. end;
  381.  
  382. procedure TADSISearch.SetUsername(const Value: WideString);
  383. begin
  384. if (FUsername <> Value) then
  385. begin
  386. FUsername := Value;
  387. end;
  388. end;
  389.  
  390. procedure TADSISearch.SetAttributes(const Value: WideString);
  391. begin
  392. if (FAttributes <> Value) then begin
  393. FAttributes := Value;
  394. end;
  395. end;
  396.  
  397. // the methods to set the search base always need to update the other property
  398. // as well, in order to make sure the base IADs interface and the BasePath
  399. // property stay in sync
  400. // setting the search base will require a new search
  401. // therefore set internal flag FSearchExecuted to false
  402. procedure TADSISearch.SetBaseIADs(const Value: IADs);
  403. begin
  404. if (FBaseIADs <> Value) then begin
  405. FBaseIADs := Value;
  406. FBasePath := FBaseIADs.ADsPath;
  407. FSearchExecuted := False;
  408. end;
  409. end;
  410.  
  411. procedure TADSISearch.SetBasePath(const Value: WideString);
  412. begin
  413. if (FBasePath <> Value) then begin
  414. FBasePath := Value;
  415. FBaseIADs := nil;
  416. FSearchExecuted := False;
  417. end;
  418. end;
  419.  
  420. procedure TADSISearch.SetChaseReferrals(const Value: Boolean);
  421. begin
  422. if (FChaseReferrals <> Value) then begin
  423. FChaseReferrals := Value;
  424. end;
  425. end;
  426.  
  427. // setting the filter will require a new search
  428. // therefore set internal flag FSearchExecuted to false
  429. procedure TADSISearch.SetFilter(const Value: WideString);
  430. begin
  431. if (FFilter <> Value) then begin
  432. FFilter := Value;
  433. FSearchExecuted := False;
  434. end;
  435. end;
  436.  
  437. procedure TADSISearch.SetMaxRows(const Value: Integer);
  438. begin
  439. if (Value >= 0) and (Value <> FMaxRows) then begin
  440. FMaxRows := Value;
  441. end;
  442. end;
  443.  
  444. procedure TADSISearch.SetPageSize(const Value: Integer);
  445. begin
  446. if (Value >= 0) and (Value <> FPageSize) then begin
  447. FPageSize := Value;
  448. end;
  449. end;
  450.  
  451. // setting the object category will require a new search
  452. // therefore set internal flag FSearchExecuted to false
  453. procedure TADSISearch.SetObjectClass(const Value: Widestring);
  454. begin
  455. if (FObjectClass <> Value) then begin
  456. if (Value = '') then
  457. FObjectClass := '*'
  458. else
  459. FObjectClass := Value;
  460. FSearchExecuted := False;
  461. end;
  462. end;
  463.  
  464. // ---------------------------------------------------------------------------
  465. // Private helper methods
  466. // ---------------------------------------------------------------------------
  467.  
  468. // EnumerateColumns iterates through all the columns in the current row of
  469. // the search results and builds the string list of results
  470. {$IFDEF UNICODE}
  471. procedure TADSISearch.EnumerateColumns(aStrList: TWideStringList);
  472. {$ELSE}
  473. procedure TADSISearch.EnumerateColumns(aStrList: TStringList);
  474. {$ENDIF}
  475. var
  476. ix : Integer;
  477. bMultiple : Boolean;
  478. pwColName : PWideChar;
  479. oSrchColumn : ads_search_column;
  480. wsColName, wsValue : WideString;
  481. begin
  482. // determine name of next column to fetch
  483. FResult := FDirSrchIntf.GetNextColumnName(FSearchHandle, pwColName);
  484.  
  485. // as long as no error occured and we still do have columns....
  486. while Succeeded(FResult) and (FResult <> S_ADS_NOMORE_COLUMNS) do begin
  487. // get the column from the result set
  488. FResult := FDirSrchIntf.GetColumn(FSearchHandle, pwColName, oSrchColumn);
  489.  
  490. if Succeeded(FResult) then begin
  491. // check if it's a multi-valued attribute
  492. bMultiple := (oSrchColumn.dwNumValues > 1);
  493.  
  494. if bMultiple then begin
  495. // if it's a multi-valued attribute, iterate through the values
  496. for ix := 0 to oSrchColumn.dwNumValues-1 do begin
  497. wsColName := Format('%s[%d]', [oSrchColumn.pszAttrName, ix]);
  498. wsValue := GetStringValue(oSrchColumn, ix);
  499. aStrList.Add(wsColName + '=' + wsValue);
  500. end;
  501. end
  502. else begin
  503. // single valued attributes are quite straightforward
  504. wsColName := oSrchColumn.pszAttrName;
  505. wsValue := GetStringValue(oSrchColumn, 0);
  506. aStrList.Add(wsColName + '=' + wsValue);
  507. end;
  508. end;
  509.  
  510. // free the memory associated with the search column, and the column name
  511. FDirSrchIntf.FreeColumn(oSrchColumn);
  512. FreeADsMem(pwColName);
  513.  
  514. // get next column name
  515. FResult := FDirSrchIntf.GetNextColumnName(FSearchHandle, pwColName);
  516. end;
  517. end;
  518.  
  519. // Get string value will turn the supported types of data into a string representation
  520. // for inclusion in the resulting string list
  521. // For a complete list of possible values, see the ADSTYPE_xxx constants in the
  522. // ActiveDs_TLB.pas file
  523. function TADSISearch.GetStringValue(oSrchColumn: ads_search_column; Index: Integer): WideString;
  524. var
  525. wrkPointer : PADSValue;
  526. oSysTime : _SYSTEMTIME;
  527. dtDate,
  528. dtTime : TDateTime;
  529. begin
  530. Result := '';
  531.  
  532. // advance the value pointer to the correct one of the potentially multiple
  533. // values in the "array of values" for this attribute
  534. wrkPointer := oSrchColumn.pADsValues;
  535. Inc(wrkPointer, Index);
  536.  
  537. // depending on the type of the value, turning it into a string is more
  538. // or less straightforward
  539. case oSrchColumn.dwADsType of
  540. ADSTYPE_CASE_EXACT_STRING : Result := wrkPointer^.__MIDL_0010.CaseExactString;
  541. ADSTYPE_CASE_IGNORE_STRING : Result := wrkPointer^.__MIDL_0010.CaseIgnoreString;
  542. ADSTYPE_DN_STRING : Result := wrkPointer^.__MIDL_0010.DNString;
  543. ADSTYPE_OBJECT_CLASS : Result := wrkPointer^.__MIDL_0010.ClassName;
  544. ADSTYPE_PRINTABLE_STRING : Result := wrkPointer^.__MIDL_0010.PrintableString;
  545. ADSTYPE_NUMERIC_STRING : Result := wrkPointer^.__MIDL_0010.NumericString;
  546. ADSTYPE_BOOLEAN : Result := IntToStr(wrkPointer^.__MIDL_0010.Boolean);
  547. ADSTYPE_INTEGER : Result := IntToStr(wrkPointer^.__MIDL_0010.Integer);
  548. ADSTYPE_LARGE_INTEGER : Result := IntToStr(wrkPointer^.__MIDL_0010.LargeInteger);
  549. ADSTYPE_UTC_TIME:
  550. begin
  551. // ADS_UTC_TIME maps to a _SYSTEMTIME structure
  552. Move(wrkPointer^.__MIDL_0010.UTCTime, oSysTime, SizeOf(oSysTime));
  553. // create two TDateTime values for the date and the time
  554. dtDate := EncodeDate(oSysTime.wYear, oSysTime.wMonth, oSysTime.wDay);
  555. dtTime := EncodeTime(oSysTime.wHour, oSysTime.wMinute, oSysTime.wSecond, oSysTime.wMilliseconds);
  556. // add the two TDateTime's (really only a Float), and turn into a string
  557. Result := DateTimeToStr(dtDate+dtTime);
  558. end;
  559. else Result := Format(rc_UnknownDataType, [oSrchColumn.dwADsType]);
  560. end;
  561. end;
  562.  
  563. // ---------------------------------------------------------------------------
  564. // Public methods
  565. // ---------------------------------------------------------------------------
  566.  
  567. // Check if any object matching the criteria as defined in the properties exists
  568. function TADSISearch.CheckIfExists(): Boolean;
  569. var
  570. {$IFDEF UNICODE}
  571. slTemp : TWideStringList;
  572. {$ELSE}
  573. slTemp : TStringList;
  574. {$ENDIF}
  575. iOldMaxRows : Integer;
  576. wsOldAttributes : WideString;
  577. begin
  578. Result := False;
  579.  
  580. // save the settings of the MaxRows and Attributes properties
  581. iOldMaxRows := FMaxRows;
  582. wsOldAttributes := FAttributes;
  583.  
  584. try
  585. // set the attributes to return just one row (that's good enough for
  586. // making sure it exists), and the Attribute of instanceType which is
  587. // one attribute that must exist for any of the ADSI objects
  588. FMaxRows := 1;
  589. FAttributes := 'instanceType';
  590.  
  591. try
  592. Search;
  593.  
  594. // did we get any results?? If so, at least one object exists!
  595. slTemp := GetFirstRow();
  596. Result := (slTemp <> nil);
  597. slTemp.Free;
  598.  
  599. except
  600. on EADSISearchException do ;
  601. end;
  602.  
  603. finally
  604. // restore the attributes to what they were before
  605. FMaxRows := iOldMaxRows;
  606. FAttributes := wsOldAttributes;
  607. end;
  608. end;
  609.  
  610. {$IFDEF UNICODE}
  611. function TADSISearch.GetFirstRow(): TWideStringList;
  612. var
  613. slTemp : TWideStringList;
  614. {$ELSE}
  615. function TADSISearch.GetFirstRow(): TStringList;
  616. var
  617. slTemp : TStringList;
  618. {$ENDIF}
  619. begin
  620. slTemp := nil;
  621.  
  622. try
  623. if FSearchExecuted then begin
  624. // get the first row of the result set
  625. FResult := FDirSrchIntf.GetFirstRow(FSearchHandle);
  626.  
  627. // did we succeed? ATTENTION: if we don't have any more rows,
  628. // we still get a "success" value back from ADSI!!
  629. if Succeeded(FResult) then begin
  630. // any more rows in the result set?
  631. if (FResult <> S_ADS_NOMORE_ROWS) then begin
  632. // create a string list
  633. {$IFDEF UNICODE}
  634. slTemp := TWideStringList.Create;
  635. {$ELSE}
  636. slTemp := TStringList.Create;
  637. {$ENDIF}
  638. // enumerate all columns into that resulting string list
  639. EnumerateColumns(slTemp);
  640. end;
  641. end
  642. else begin
  643. raise EADSISearchException.CreateFmt(rc_GetFirstFailed, [FResult]);
  644. end;
  645. end
  646. else begin
  647. raise EADSISearchException.Create(rc_SearchNotExec);
  648. end;
  649.  
  650. finally
  651. Result := slTemp;
  652. end;
  653. end;
  654.  
  655. {$IFDEF UNICODE}
  656. function TADSISearch.GetNextRow(): TWideStringList;
  657. var
  658. slTemp : TWideStringList;
  659. {$ELSE}
  660. function TADSISearch.GetNextRow(): TStringList;
  661. var
  662. slTemp : TStringList;
  663. {$ENDIF}
  664. begin
  665. slTemp := nil;
  666.  
  667. try
  668. if FSearchExecuted then begin
  669. // get the next row of the result set
  670. FResult := FDirSrchIntf.GetNextRow(FSearchHandle);
  671.  
  672. // did we succeed? ATTENTION: if we don't have any more rows,
  673. // we still get a "success" value back from ADSI!!
  674. if Succeeded(FResult) then begin
  675. // any more rows in the result set?
  676. if (FResult <> S_ADS_NOMORE_ROWS) then begin
  677. // create result string list
  678. {$IFDEF UNICODE}
  679. slTemp := TWideStringList.Create;
  680. {$ELSE}
  681. slTemp := TStringList.Create;
  682. {$ENDIF}
  683. // enumerate all columns in result set
  684. EnumerateColumns(slTemp);
  685. end;
  686. end
  687. else begin
  688. raise EADSISearchException.CreateFmt(rc_GetNextFailed, [FResult]);
  689. end;
  690. end
  691. else begin
  692. raise EADSISearchException.Create(rc_SearchNotExec);
  693. end;
  694.  
  695. finally
  696. Result := slTemp;
  697. end;
  698. end;
  699.  
  700. // this is the core piece of the component - the actual search method
  701. procedure TADSISearch.Search;
  702. var
  703. ix : Integer;
  704. wsFilter : WideString;
  705. {$IFDEF UNICODE}
  706. slTemp : TWideStringList;
  707. {$ELSE}
  708. slTemp : TStringList;
  709. {$ENDIF}
  710. AttrCount : Cardinal;
  711. AttrArray : array of WideString;
  712. SrchPrefInfo : array of ads_searchpref_info;
  713. DSO :IADsOpenDSObject;
  714. Dispatch:IDispatch;
  715.  
  716. begin
  717. // check to see if we have assigned an IADs, if not, bind to it
  718. if (FBaseIADs = nil) then begin
  719. ADsGetObject('LDAP:', IID_IADsOpenDSObject, DSO);
  720. Dispatch := DSO.OpenDSObject(FBasePath, FUsername, FPassword, ADS_SECURE_AUTHENTICATION);
  721. FResult := Dispatch.QueryInterface(IID_IADs, FBaseIADs);
  722. //FResult := ADsGetObject(@FBasePath[1], IID_IADs, FBaseIADs);
  723.  
  724. if not Succeeded(FResult) then begin
  725. raise EADSISearchException.CreateFmt(rc_CouldNotBind, [FBasePath, FResult]);
  726. end;
  727. end;
  728.  
  729. // get the IDirectorySearch interface from the base object
  730. FDirSrchIntf := (FBaseIADs as IDirectorySearch);
  731.  
  732. if (FDirSrchIntf = nil) then begin
  733. raise EADSISearchException.CreateFmt(rc_CouldNotGetIDS, [FBasePath, FResult]);
  734. end;
  735.  
  736. // if we still have a valid search handle => close it
  737. if (FSearchHandle <> 0) then begin
  738. FResult := FDirSrchIntf.CloseSearchHandle(FSearchHandle);
  739.  
  740. if not Succeeded(FResult) then begin
  741. raise EADSISearchException.CreateFmt(rc_CouldNotFreeSH, [FResult]);
  742. end;
  743. end;
  744.  
  745. // we are currently setting 3 search preferences
  746. // for a complete list of possible search preferences, please check
  747. // the ADS_SEARCHPREF_xxx values in ActiveDs_TLB.pas
  748. SetLength(SrchPrefInfo, 4);
  749.  
  750. // Set maximum number of rows to be what is defined in the MaxRows property
  751. SrchPrefInfo[0].dwSearchPref := ADS_SEARCHPREF_SIZE_LIMIT;
  752. SrchPrefInfo[0].vValue.dwType := ADSTYPE_INTEGER;
  753. SrchPrefInfo[0].vValue.__MIDL_0010.Integer := FMaxRows;
  754.  
  755. // set the "chase referrals" search preference
  756. SrchPrefInfo[1].dwSearchPref := ADS_SEARCHPREF_CHASE_REFERRALS;
  757. SrchPrefInfo[1].vValue.dwType := ADSTYPE_BOOLEAN;
  758. SrchPrefInfo[1].vValue.__MIDL_0010.Boolean := Ord(FChaseReferrals);
  759.  
  760. // set the "search scope" search preference
  761. SrchPrefInfo[2].dwSearchPref := ADS_SEARCHPREF_SEARCH_SCOPE;
  762. SrchPrefInfo[2].vValue.dwType := ADSTYPE_INTEGER;
  763. SrchPrefInfo[2].vValue.__MIDL_0010.Integer := Ord(FSearchScope);
  764.  
  765. // set the "page size " search preference
  766. SrchPrefInfo[3].dwSearchPref := ADS_SEARCHPREF_PAGESIZE;
  767. SrchPrefInfo[3].vValue.dwType := ADSTYPE_INTEGER;
  768. SrchPrefInfo[3].vValue.__MIDL_0010.Integer := FPageSize;
  769.  
  770. // set the search preferences of our directory search interface
  771. FResult := FDirSrchIntf.SetSearchPreference(Pointer(SrchPrefInfo), Length(SrchPrefInfo));
  772.  
  773. if not Succeeded(FResult) then begin
  774. raise EADSISearchException.CreateFmt(rc_SetSrchPrefFailed,
  775.  
  776. unit ADSI;
  777.  
  778. interface
  779.  
  780. uses
  781. SysUtils, Classes, ActiveX, Windows, ComCtrls, ExtCtrls, ActiveDs_TLB,
  782. adshlp, oleserver, Variants;
  783.  
  784. type
  785. TPassword = record
  786. Expired: boolean;
  787. NeverExpires: boolean;
  788. CannotChange: boolean;
  789. end;
  790.  
  791. type
  792. TADSIUserInfo = record
  793. UID: string;
  794. UserName: string;
  795. Description: string;
  796. Password: TPassword;
  797. Disabled: boolean;
  798. LockedOut: boolean;
  799. Groups: string; //CSV
  800. end;
  801.  
  802. type
  803. TADSI = class(TComponent)
  804.  
  805. private
  806. FUserName: string;
  807. FPassword: string;
  808. FCurrentUser: string;
  809. FCurrentDomain: string;
  810.  
  811. function GetCurrentUserName: string;
  812. function GetCurrentDomain: string;
  813.  
  814.  
  815. protected
  816. { Protected declarations }
  817. public
  818. constructor Create(AOwner: TComponent); override;
  819. destructor Destroy; override;
  820.  
  821. property CurrentUserName: string read FCurrentUser;
  822. property CurrentDomain: string read FCurrentDomain;
  823.  
  824. function GetUser(Domain, UserName: string; var ADSIUser: TADSIUserInfo): boolean;
  825. function Authenticate(Domain, UserName, Group: string): boolean;
  826.  
  827. published
  828. property LoginUserName: string read FUserName write FUserName;
  829. property LoginPassword: string read FPassword write FPassword;
  830. end;
  831.  
  832. procedure Register;
  833.  
  834. implementation
  835.  
  836.  
  837. function ContainsValComma(s1,s: string): boolean;
  838. var
  839. sub,str: string;
  840. begin
  841. Result:=false;
  842. if (s='') or (s1='') then exit;
  843. if SameText(s1,s) then begin
  844. Result:=true;
  845. exit;
  846. end;
  847. sub:=','+lowercase(trim(s1))+','; str:=','+lowercase(trim(s))+',';
  848. Result:=(pos(sub, str)>0);
  849. end;
  850.  
  851. procedure Register;
  852. begin
  853. RegisterComponents('ADSI', [TADSI]);
  854. end;
  855.  
  856. constructor TADSI.Create(AOwner: TComponent);
  857. begin
  858. inherited Create(AOwner);
  859.  
  860. FCurrentUser:=GetCurrentUserName;
  861. FCurrentDomain:=GetCurrentDomain;
  862. FUserName:='';
  863. FPassword:='';
  864. end;
  865.  
  866. destructor TADSI.Destroy;
  867. begin
  868.  
  869. inherited Destroy;
  870. end;
  871.  
  872. function TADSI.GetCurrentUserName : string;
  873. const
  874. cnMaxUserNameLen = 254;
  875. var
  876. sUserName : string;
  877. dwUserNameLen : DWord;
  878. begin
  879. dwUserNameLen := cnMaxUserNameLen-1;
  880. SetLength(sUserName, cnMaxUserNameLen );
  881. GetUserName(PChar(sUserName), dwUserNameLen );
  882. SetLength(sUserName, dwUserNameLen);
  883. Result := sUserName;
  884. end;
  885.  
  886. function TADSI.GetCurrentDomain: string;
  887. const
  888. DNLEN = 255;
  889. var
  890. sid : PSID;
  891. sidSize : DWORD;
  892. sidNameUse : DWORD;
  893. domainNameSize : DWORD;
  894. domainName : array[0..DNLEN] of char;
  895.  
  896. begin
  897. sidSize := 65536;
  898. GetMem(sid, sidSize);
  899. domainNameSize := DNLEN + 1;
  900. sidNameUse := SidTypeUser;
  901. try
  902. if LookupAccountName(nil, PChar(FCurrentUser), sid, sidSize,
  903. domainName, domainNameSize, sidNameUse) then
  904. Result:=StrPas(domainName);
  905. finally
  906. FreeMem(sid);
  907. end;
  908. end;
  909.  
  910. function TADSI.Authenticate(Domain, UserName, Group: string): boolean;
  911. var
  912. aUser: TADSIUserInfo;
  913. begin
  914. Result:=false;
  915. if GetUser(Domain,UserName,aUser) then begin
  916. if not aUser.Disabled and not aUser.LockedOut then begin
  917. if Group='' then
  918. Result:=true
  919. else
  920. Result:=ContainsValComma(Group, aUser.Groups);
  921. end;
  922. end;
  923. end;
  924.  
  925. function TADSI.GetUser(Domain, UserName: string; var ADSIUser: TADSIUserInfo): boolean;
  926. var
  927. usr : IAdsUser;
  928. flags : integer;
  929. Enum : IEnumVariant;
  930. grps : IAdsMembers;
  931. grp : IAdsGroup;
  932. varGroup : OleVariant;
  933. Temp : LongWord;
  934. dom1, uid1: string;
  935.  
  936. //ui: TADSIUserInfo;
  937.  
  938. begin
  939. ADSIUser.UID:='';
  940. ADSIUser.UserName:='';
  941. ADSIUser.Description:='';
  942. ADSIUser.Disabled:=true;
  943. ADSIUser.LockedOut:=true;
  944. ADSIUser.Groups:='';
  945. Result:=false;
  946.  
  947. if UserName='' then
  948. uid1:=FCurrentUser
  949. else
  950. uid1:=UserName;
  951.  
  952. if Domain='' then
  953. dom1:=FCurrentDomain
  954. else
  955. dom1:=Domain;
  956.  
  957. if uid1='' then exit;
  958. if dom1='' then exit;
  959.  
  960. try
  961. if trim(FUserName)<>'' then
  962. ADsOpenObject('WinNT://' + dom1 + '/' + uid1, FUserName, FPassword, 1, IADsUser, usr)
  963. else
  964. ADsGetObject('WinNT://' + dom1 + '/' + uid1, IADsUser, usr);
  965.  
  966. if usr=nil then exit;
  967.  
  968. ADSIUser.UID:= UserName;
  969. ADSIUser.UserName := usr.FullName;
  970. ADSIUser.Description := usr.Description;
  971. flags := usr.Get('userFlags');
  972. ADSIUser.Password.Expired := usr.Get('PasswordExpired');
  973. ADSIUser.Password.CannotChange := (flags AND ADS_UF_PASSWD_CANT_CHANGE)<>0;
  974. ADSIUser.Password.NeverExpires := (flags and ADS_UF_DONT_EXPIRE_PASSWD)<>0;
  975. ADSIUser.Disabled := usr.AccountDisabled;
  976. ADSIUser.LockedOut := usr.IsAccountLocked;
  977.  
  978. ADSIUser.Groups:='';
  979. grps := usr.Groups;
  980. Enum := grps._NewEnum as IEnumVariant;
  981. if Enum <> nil then begin
  982. while (Enum.Next(1,varGroup, Temp) = S_OK) do begin
  983. grp := IDispatch(varGroup) as IAdsGroup;
  984. //sGroupType := GetGroupType(grp);
  985. if ADSIUser.Groups<>'' then ADSIUser.Groups:=ADSIUser.Groups+',';
  986. ADSIUser.Groups:=ADSIUser.Groups+grp.Name;
  987. VariantClear(varGroup);
  988. end;
  989. end;
  990. usr:=nil;
  991. Result:=true;
  992. except
  993. on e: exception do begin
  994. Result:=false;
  995. exit;
  996. end;
  997. end;
  998. end;
  999.  
  1000. end.
Add Comment
Please, Sign In to add comment