Добавление и удаление общих сетевых ресурсов

Материал из DRKB


{*******************************************************}
{                                                       }
{       Добавление и удаление общих сетевых ресурсов    }
{                                                       }
{ Copyright (c)                                         }
{    1998-2002 Rouse_                                   }
{              (базовый код, взят из примера NetMon)    }
{    2006 Smike                                         }
{              (- доработка для возможности создания    }
{                 ресурсов, открытых только для чтения  }
{                 под NT/2000/XP/2003,                  }
{               - небольшой рефакторинг ;) )            }
{                                                       }
{*******************************************************}

unit Shares;

interface

uses
  Windows, SysUtils, AclApi;

function ShareDirectory(const Directory: string): DWORD;
function UnShareDirectory(const Directory: string): DWORD;

implementation

const
  STYPE_DISKTREE = 0;

function ShareDirectoryNT(const Directory, ShareName: string): DWORD;
type
  TShareInfo502 = packed record
    shi502_netname : PWChar;
    shi502_type: DWORD;
    shi502_remark :PWChar;
    shi502_permissions: DWORD;
    shi502_max_uses : DWORD;
    shi502_current_uses : DWORD;
    shi502_path : PWChar;
    shi502_passwd : PWChar;
    shi502_reserved: DWORD;
    shi502_security_descriptor: PSECURITY_DESCRIPTOR;
  end;
const
  ACL_REVISION = 2;
  SECURITY_WORLD_SID_AUTHORITY: TSidIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 1));
  SECURITY_WORLD_RID = ($00000000);
  SECURITY_NT_AUTHORITY: TSidIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));
  SECURITY_BUILTIN_DOMAIN_RID = ($00000020);
  DOMAIN_ALIAS_RID_ADMINS = ($00000220);
var
  NetShareAddNT: function(servername: PWideChar;
                          level: DWORD;
                          buf: Pointer;
                          parm_err: LPDWORD): DWORD; stdcall;
  ShareNT: TShareInfo502;
  FLibHandle: THandle;
  TmpDirNT, TmpNameNT: PWChar;
  TmpLength: Integer;
  pSd: PSECURITY_DESCRIPTOR;
  pDacl: PACL;
  EveryoneSid, AdminSid: Pointer;
begin
  Result := DWORD(-1);
  FLibHandle := LoadLibrary('NETAPI32.DLL');
  if FLibHandle = 0 then Exit;
  try
    NetShareAddNT := GetProcAddress(FLibHandle,'NetShareAdd');
    if not Assigned(NetShareAddNT) then Exit;

    TmpLength := SizeOf(WideChar) * 256; // Определяем необходимый размер

    GetMem(TmpNameNT, TmpLength); // Конвертируем в PWChar
    StringToWideChar(ShareName, TmpNameNT, TmpLength);
    ShareNT.shi502_netname := TmpNameNT; // Имя

    ShareNT.shi502_type := STYPE_DISKTREE; // Тип ресурса
    ShareNT.shi502_remark := ''; // Комментарий
    // В NT, 2000, XP, 2003 разрешения на уровне расшаренной папки не поддерживается
    // Для этого задаем ниже атрибуты доступа на уровне групп
    ShareNT.shi502_permissions := 0;
    ShareNT.shi502_max_uses := DWORD(-1); // Кол-во максим. подключений
    ShareNT.shi502_current_uses := 0; // Кол-во текущих подключений

    GetMem(TmpDirNT, TmpLength);
    StringToWideChar(Directory, TmpDirNT, TmpLength);
    ShareNT.shi502_path := TmpDirNT; // Путь к ресурсу

    ShareNT.shi502_passwd := ''; // Пароль

    ShareNT.shi502_reserved := 0;

    // Здесь начинается самое интересное - задаем разрешения :)
    GetMem(pDacl, 256);
    InitializeAcl(pDacl^, 256, ACL_REVISION);
    EveryoneSid := nil;
    AdminSid := nil;
    AllocateAndInitializeSid(SECURITY_WORLD_SID_AUTHORITY, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, EveryoneSid);
    AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, AdminSid);
    AddAccessAllowedAce(pDacl^, ACL_REVISION, GENERIC_ALL, AdminSid);
    AddAccessAllowedAce(pDacl^, ACL_REVISION, (GENERIC_READ or GENERIC_EXECUTE or READ_CONTROL or STANDARD_RIGHTS_READ), EveryoneSid);
    GetMem(pSd, SECURITY_DESCRIPTOR_MIN_LENGTH);
    InitializeSecurityDescriptor(pSd, SECURITY_DESCRIPTOR_REVISION);
    SetSecurityDescriptorDacl(pSd, TRUE, pDacl, FALSE);
    ShareNT.shi502_security_descriptor := pSd;

    Result := NetShareAddNT(nil, 502, @ShareNT, nil); // Добавляем ресурс

    if Assigned(EveryoneSid) then
      FreeSid(EveryoneSid);

    if Assigned(AdminSid) then
      FreeSid(AdminSid);

    // освобождаем память
    FreeMem(pDacl);
    FreeMem(pSd);
    FreeMem(TmpNameNT);
    FreeMem(TmpDirNT);
  finally
    FreeLibrary(FLibHandle);
  end;
end;

function ShareDirectory9x(const Directory, ShareName: string): DWORD;
type
  TShareInfo50 = packed record
    shi50_netname : array [0..12] of Char;
    shi50_type : Byte;
    shi50_flags : Word;
    shi50_remark : PChar;
    shi50_path : PChar;
    shi50_rw_password : array [0..8] of Char;
    shi50_ro_password : array [0..8] of Char;
  end;
const
  SHI50F_RDONLY  = $1;
var
  NetShareAdd: function(pszServer: PAnsiChar;
                        sLevel: Cardinal;
                        pbBuffer: PAnsiChar;
                        cbBuffer: Word):DWORD; stdcall;
  Share9x: TShareInfo50;
  FLibHandle: THandle;
begin
  Result := DWORD(-1);
  FLibHandle := LoadLibrary('SVRAPI.DLL');
  if FLibHandle = 0 then Exit;
  try
    NetShareAdd := GetProcAddress(FLibHandle,'NetShareAdd');
    if not Assigned(NetShareAdd) then Exit;

    FillChar(Share9x.shi50_netname, SizeOf(Share9x.shi50_netname), #0);
    Move(ShareName[1], Share9x.shi50_netname[0], Length(ShareName)); // Имя
    Share9x.shi50_type := STYPE_DISKTREE; // Тип ресурса
    Share9x.shi50_flags := SHI50F_RDONLY; // Доступ
    FillChar(Share9x.shi50_remark,
      SizeOf(Share9x.shi50_remark), #0); // Комментарий
    FillChar(Share9x.shi50_path,
      SizeOf(Share9x.shi50_path), #0);
    Share9x.shi50_path := PAnsiChar(Directory); // Путь к ресурсу
    FillChar(Share9x.shi50_rw_password,
      SizeOf(Share9x.shi50_rw_password), #0); // Пароль полного доступа
    FillChar(Share9x.shi50_ro_password,
      SizeOf(Share9x.shi50_ro_password), #0); // Пароль для чтения
    Result := NetShareAdd(nil, 50, @Share9x, SizeOf(Share9x));
  finally
    FreeLibrary(FLibHandle);
  end;
end;

function ShareDirectory(const Directory: string): DWORD;
var
  ShareDir, ShareName: string;
begin
  ShareDir := ExcludeTrailingPathDelimiter(Directory);
  ShareName := ExtractFileName(ShareDir);

  if Win32Platform = VER_PLATFORM_WIN32_NT then
    Result := ShareDirectoryNT(ShareDir, ShareName)
  else
    Result := ShareDirectory9x(ShareDir, ShareName);
end;

function UnShareDirectoryNT(const ShareName: string): DWORD;
var
  FLibHandle: THandle;
  NameNT: PWChar;
  NetShareDelNT: function(servername: PWideChar;
                          netname: PWideChar;
                          reserved: DWORD): LongInt; stdcall;
  Size: Integer;
begin
  Result := DWORD(-1);
  FLibHandle := LoadLibrary('NETAPI32.DLL');
  if FLibHandle = 0 then Exit;
  try
    NetShareDelNT := GetProcAddress(FLibHandle, 'NetShareDel');
    if not Assigned(NetShareDelNT) then // Проверка
    begin
      FreeLibrary(FLibHandle);
      Exit;
    end;
    Size := SizeOf(WideChar) * 256;
    GetMem(NameNT, Size);  // Выделяем память под переменную
    StringToWideChar(ShareName, NameNT, Size); // Преобразуем в PWideChar
    NetShareDelNT(nil, NameNT, 0);   // Удаляем ресурс
    FreeMem(NameNT);  // Освобождаем память
  finally
    FreeLibrary(FLibHandle);
  end;
end;

function UnShareDirectory9x(const ShareName: string): DWORD;
var
  FLibHandle: THandle;
  Name9x: array [0..12] of Char;
  NetShareDel: function(pszServer,
                        pszNetName: PChar;
                        usReserved: Word): DWORD; stdcall;
begin
  Result := DWORD(-1);
  FLibHandle := LoadLibrary('SVRAPI.DLL');
  if FLibHandle = 0 then Exit;
  try
    NetShareDel := GetProcAddress(FLibHandle,'NetShareDel');
    if not Assigned(NetShareDel) then Exit;
    FillChar(Name9x, SizeOf(Name9x), #0); // Очищаем массив
    Move(ShareName[1], Name9x[0], Length(ShareName)); // Заполняем массив
    Result := NetShareDel(nil, @Name9x, 0); // Удаляем ресурс
  finally
    FreeLibrary(FLibHandle);
  end;
end;

function UnShareDirectory(const Directory: string): DWORD;
var
  ShareName: string;
begin
  ShareName := ExtractFileName(ExcludeTrailingPathDelimiter(Directory));

  if Win32Platform = VER_PLATFORM_WIN32_NT then       // Код для NT
    Result := UnShareDirectoryNT(ShareName)
  else                                                // Код для 9х-Ме
    Result := UnShareDirectory9x(ShareName);
end;

end.


Author: Rouse_, Smike
Source: http://forum.sources.ru
ID: 03317