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 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
| unit hives;
interface
uses Windows, SysUtils, Registry;
type TUtilisateur = record
Nom, SID, Ruche: string;
Logged: bool;
end;
TUtilisateurs= array of TUtilisateur;
TChargementRuche = record
Backup: bool;
Restore: bool;
CodeErreur: DWORD;
end;
const ERROR_SIDUNREACHABLE = 1;
ERROR_HIVEUNREACHABLE = 2;
ERROR_UNABLE = 3;
// Permet de récupérer la liste des utilisateurs dans un tableau comprenant pour chacun
// son nom, son SID (format chaîne), et le nom court de son fichier ruche NTUSER.DAT
// Si TousLesComptes est à false, seuls les comptes d'utilisateurs réels sont listés,
// sinon la fonction renvoie la liste complète des utilisateurs
function ListerUtilisateurs(TousLesComptes: bool): TUtilisateurs;
// Charge dans le registre le fichier ruche de l'utilisateur dont le rang de la liste est précisé
// et renvoie l'état initial des droits d'accès au registre
// Result.CodeErreur Renvoie
// ERROR_SIDUNREACHABLE si le SID de l'utilisateur est inaccessible
// ERROR_HIVEUNREACHABLE si le fichier ruche est introuvable
// ERROR_UNABLE en cas de problème de chargement de la clé
// ERROR_SUCCESS sinon
// Result.Backup et Result.Restore sont mémorisés pour le déchargement
function ChargerRucheUtilisateur(Utilisateurs: TUtilisateurs ; NumeroUtilisateur: integer): TChargementRuche;
// Décharge du registre le fichier ruche de l'utilisateur dont le rang de la liste est précisé
// et rétablit les droits d'accès au registre tels que spécifiés dans ChargementRuche
// Renvoie
// ERROR_UNABLE en cas de problème de déchargement de la clé
// ERROR_SUCCESS sinon
function DechargerRucheUtilisateur(Utilisateurs: TUtilisateurs ; NumeroUtilisateur: integer; ChargementRuche: TChargementRuche): DWORD;
// Permet de retrouver le rang d'un utilisateur dans une liste d'utilisateurs à partir de son nom
// (cette fonction n'est pas sensible aux majuscules/minuscules)
function RangUtilisateur(Utilisateurs: TUtilisateurs ; NomUtilisateur: string): integer;
implementation
// Permet de retrouver le rang d'un utilisateur dans une liste d'utilisateurs à partir de son nom
// (cette fonction n'est pas sensible aux majuscules/minuscules)
function RangUtilisateur(Utilisateurs: TUtilisateurs ; NomUtilisateur: string): integer;
var Trouve: bool;
i: integer;
begin
Trouve:=false; i:=0;
while (i<=length(Utilisateurs)-1) and not Trouve do
if UpperCase(Utilisateurs[ i].Nom)=UpperCase(NomUtilisateur) then Trouve:=true else i:=i+1;
if i<=length(Utilisateurs)-1 then result:=i else result:=-1;
end;
// Permet de récupérer la liste des utilisateurs dans un tableau comprenant pour chacun
// son nom, son SID (format chaîne), et le nom court de son fichier ruche NTUSER.DAT
function ListerUtilisateurs(TousLesComptes: bool): TUtilisateurs;
// transforme %WINDIR% en C:\Windows ; %systemroot% en c:\, etc...
function ExpandEnvStr(const szInput: string): string;
const MAXSIZE = 32768;
begin
SetLength(Result,MAXSIZE);
SetLength(Result,ExpandEnvironmentStrings(pchar(szInput),
@Result[1],length(Result)));
result:=PChar(result);
end;
// transforme un nom long de fichier en nom court
function NomCourt(Fichier: TFileName): TFileName;
var Temp: array[0..MAX_PATH-1]of char;
begin
GetShortPathName(PChar(Fichier),Temp,SizeOf(Temp));
result:=String(Temp);
end;
type USER_INFO_1 = record
usri1_name: LPWSTR;
usri1_password: LPWSTR;
usri1_password_age: DWORD;
usri1_priv: DWORD;
usri1_home_dir: LPWSTR;
usri1_comment: LPWSTR;
usri1_flags: DWORD;
usri1_script_path: LPWSTR;
end;
lpUSER_INFO_1 = ^USER_INFO_1;
const // chemin du registre HKLM où les répertoires des comptes utilisateurs sont stockés
ProfilePath='\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\';
ProfileValue='ProfileImagePath';
// nom du fichier ruche sous NT
NTUSER='NTUser.dat';
// nom de la DLL utilisée pour énumérer les utilisateurs
netapi32='netapi32.dll';
HEAP_ZERO_MEMORY = $00000008;
SID_REVISION = 1;
DNLEN = 15;
var EntiesRead: DWORD;
TotalEntries: DWORD;
UserInfo: lpUSER_INFO_1;
lpBuffer: Pointer;
Counter: integer;
ResumeHandle: DWORD;
NetApiStatus: LongWord;
Sid: Pointer;
sidSize : DWORD;
domainNameSize : DWORD;
domainName : array [0..DNLEN + 1] of char;
sidNameUse : SID_NAME_USE;
szSid: PChar;
Reg, Reg2: TRegistry;
Temp: string;
ConvertSidToStringSidFunction: PChar;
hConvertSidToStringSid, hNetUserEnum, hNetApiBufferFree: THandle;
ConvertSidToStringSid: function(SID: PSID; var StringSid: LPSTR):LongBool; stdcall;
NetUserEnum: function(ServerName: PWideChar; Level, Filter: DWORD; var Buffer: Pointer; PrefMaxLen: DWORD; var EntriesRead, TotalEntries, ResumeHandle: DWORD): Longword; stdcall;
NetApiBufferFree: function(pBuffer: PByte):Longint; stdcall;
begin
// Teste la disponibilité des librairies et fonctions utilisées
hConvertSidToStringSid:=LoadLibrary(PChar(advapi32)); if hConvertSidToStringSid=0 then exit;
{$IFDEF UNICODE}
ConvertSidToStringSidFunction:='ConvertSidToStringSidW';
{$ELSE}
ConvertSidToStringSidFunction:='ConvertSidToStringSidA';
{$ENDIF}
@ConvertSidToStringSid:=GetProcAddress(hConvertSidToStringSid,ConvertSidToStringSidFunction);
if @ConvertSidToStringSid=nil then exit;
hNetUserEnum:=LoadLibrary(PChar(netapi32)); if hNetUserEnum=0 then exit;
@NetUserEnum:=GetProcAddress(hNetUserEnum,'NetUserEnum');
if @NetUserEnum=nil then exit;
hNetApiBufferFree:=LoadLibrary(PChar(netapi32)); if hNetApiBufferFree=0 then exit;
@NetApiBufferFree:=GetProcAddress(hNetApiBufferFree,'NetApiBufferFree');
if @NetApiBufferFree=nil then exit;
// Début de la recherche des utilisateurs
Setlength(result,0);
ResumeHandle := 0;
Reg:= TRegistry.Create; Reg.RootKey:=HKEY_USERS; Reg.Access:=KEY_READ;
Reg2:= TRegistry.Create; Reg2.RootKey:=HKEY_LOCAL_MACHINE; Reg2.Access:=KEY_READ;
repeat
NetApiStatus := NetUserEnum('srvibm2.sinfoni.local', 1, 0, lpBuffer, 0, EntiesRead, TotalEntries, ResumeHandle);
UserInfo := lpBuffer;
if EntiesRead>0 then // ligne ajoutée pour éviter des messages d'erreur en cas de directive {$R+} or {$Q+}
for Counter:=0 to EntiesRead-1 do begin
if (WideCharToString(UserInfo^.usri1_comment)='') or TousLesComptes then begin
Setlength(result,length(result)+1);
// On récupère le nom de l'utilisateur recensé
result[length(result)-1].Nom:=WideCharToString(UserInfo^.usri1_name);
result[length(result)-1].SID:='';
result[length(result)-1].Ruche:='';
result[length(result)-1].Logged:=false;
sidSize := 65536;
GetMem (sid, sidSize);
domainNameSize := DNLEN + 1;
// On utilise LookupAccountName pour récupérer le SID de l'utilisateur précisé
if LookupAccountName (nil, PChar(result[length(result)-1].Nom), sid, sidSize, domainName, domainNameSize, sidNameUse) and ConvertSidToStringSid(SID, szSID) then begin
result[length(result)-1].SID:=szSID;
// On teste la présence de la branche correspondant au SID dans HKEY_USERS
// Si la branche existe l'utilisateur s'est déjà logué, sinon non
if Reg.KeyExists(szSID) then result[length(result)-1].Logged:=true;
// On ouvre la clé HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\[SID]
// pour récupérer le nom du fichier ruche de l'utilisateur concerné
if Reg2.OpenKey(ProfilePath+szSID, false) then
begin
Temp:=ExpandEnvStr(Reg2.ReadString(ProfileValue));
if DirectoryExists(Temp) then
begin
Temp:=IncludeTrailingPathDelimiter(Temp);
if FileExists(Temp+NTUSER) then result[length(result)-1].Ruche:=NomCourt(Temp+NTUSER);
end;
end;
Reg2.CloseKey;
end;
end;
Inc(UserInfo);
end;
NetApiBufferFree(lpBuffer);
until (NetApiStatus <> ERROR_MORE_DATA);
Reg.Free; Reg2.Free;
FreeLibrary(hConvertSidToStringSid); FreeLibrary(hNetUserEnum); FreeLibrary(hNetApiBufferFree);
end;
// Modification des privilèges pour l'accès au registre (permet d'utiliser LoadKey et UnLoadKey)
function SetPrivilege(Privilege: PChar; EnablePrivilege: Boolean; out PreviousState: Boolean): DWORD;
var
Token: THandle;
NewState: TTokenPrivileges;
Luid: TLargeInteger;
PrevState: TTokenPrivileges;
Return: DWORD;
begin
PreviousState := True;
if (GetVersion() > $80000000) then
Result := ERROR_SUCCESS
else
begin
if not OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, Token) then
Result := GetLastError()
else
try
if not LookupPrivilegeValue(nil, Privilege, Luid) then
Result := GetLastError()
else
begin
NewState.PrivilegeCount := 1;
NewState.Privileges[0].Luid := Luid;
if EnablePrivilege then
NewState.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED
else
NewState.Privileges[0].Attributes := 0;
if not AdjustTokenPrivileges(Token, False, NewState,
SizeOf(TTokenPrivileges), PrevState, Return) then
Result := GetLastError()
else
begin
Result := ERROR_SUCCESS;
PreviousState :=
(PrevState.Privileges[0].Attributes and SE_PRIVILEGE_ENABLED <> 0);
end;
end;
finally
CloseHandle(Token);
end;
end;
end;
// Charge dans le registre le fichier ruche de l'utilisateur dont le rang de la liste est précisé
// et renvoie l'état initial des droits d'accès au registre
// Result.CodeErreur Renvoie
// ERROR_SIDUNREACHABLE si le SID de l'utilisateur est inaccessible
// ERROR_HIVEUNREACHABLE si le fichier ruche est introuvable
// ERROR_UNABLE en cas de problème de chargement de la clé
// ERROR_SUCCESS sinon
// Result.Backup et Result.Restore sont mémorisés pour le déchargement
function ChargerRucheUtilisateur(Utilisateurs: TUtilisateurs ; NumeroUtilisateur: integer): TChargementRuche;
const SE_BACKUP_NAME = 'SeBackupPrivilege';
SE_RESTORE_NAME = 'SeRestorePrivilege';
var
PrevBackup: Boolean;
PrevRestore: Boolean;
Reg: TRegistry;
begin
if Utilisateurs[NumeroUtilisateur].SID='' then begin Result.CodeErreur:=ERROR_SIDUNREACHABLE; exit; end;
if not FileExists(Utilisateurs[NumeroUtilisateur].Ruche) then begin Result.CodeErreur:=ERROR_HIVEUNREACHABLE; exit; end;
Result.CodeErreur := SetPrivilege(SE_BACKUP_NAME, True, PrevBackup);
if (Result.CodeErreur = ERROR_SUCCESS) then
try
Result.CodeErreur := SetPrivilege(SE_RESTORE_NAME, True, PrevRestore);
if (Result.CodeErreur = ERROR_SUCCESS) then
try
Reg:= TRegistry.create;
Reg.Rootkey:= HKEY_USERS;
if not Reg.Loadkey(Utilisateurs[NumeroUtilisateur].SID, Utilisateurs[NumeroUtilisateur].Ruche) then
Result.CodeErreur:=ERROR_UNABLE;
Reg.Free;
except;
Result.CodeErreur:=ERROR_UNABLE;
end;
except
Result.CodeErreur:=ERROR_UNABLE;
end;
Result.Backup:=PrevBackup;
Result.Restore:=PrevRestore;
end;
// Décharge du registre le fichier ruche de l'utilisateur dont le rang de la liste est précisé
// et rétablit les droits d'accès au registre tels que spécifiés dans ChargementRuche
// Renvoie
// ERROR_UNABLE en cas de problème de déchargement de la clé
// ERROR_SUCCESS sinon
function DechargerRucheUtilisateur(Utilisateurs: TUtilisateurs ; NumeroUtilisateur: integer; ChargementRuche: TChargementRuche): DWORD;
const SE_BACKUP_NAME = 'SeBackupPrivilege';
SE_RESTORE_NAME = 'SeRestorePrivilege';
var PrevRestore, PrevBackup: Boolean;
Reg: TRegistry;
begin
Result:=ERROR_SUCCESS;
PrevRestore:=ChargementRuche.Restore;
PrevBackup:=ChargementRuche.Backup;
try
Reg:= TRegistry.create;
Reg.Rootkey:= HKEY_USERS;
if not Reg.UnLoadKey(Utilisateurs[NumeroUtilisateur].SID) then Result:=ERROR_UNABLE;
Reg.Free;
except
Result:=Error_UNABLE;
end;
if (PrevRestore) then Result:=SetPrivilege(SE_RESTORE_NAME, PrevRestore, PrevRestore);
if (not PrevBackup) then Result:=SetPrivilege(SE_BACKUP_NAME, PrevBackup, PrevBackup);
end;
end. |
Partager